C#实现范型二叉堆

二叉堆结构解释: http://www.apkbus.com/android-58533-1-1.html

 

代码实现方式:

using System;
using System.Collections.Generic;

namespace BinaryHeap
{
    /// <summary>
    /// 排序的枚举
    /// </summary>
    public enum Order
    {
        ASC = 0,
        DESC = 1
    }

    /// <summary>
    /// 二叉堆
    /// </summary>
    /// <typeparam name="T">填入你需要存储的类型</typeparam>
    public class BinaryHeap<T> where T : IComparable<T>
    {
        /// <summary>
        /// The size of the heap
        /// </summary>
        public int Size { get; set; }

        private int length;
        /// <summary>
        /// 堆的长度
        /// </summary>
        public int Length
        {
            get
            {
                return length;
            }
            private set { length = value; }
        }

        private T[] Items { get; set; }
        private Order Order = Order.ASC;

        /// <summary>
        /// The Cons of the heap
        /// </summary>
        /// <param name="size">The default size of the heap</param>
        /// <param name="order">The order of the heap</param>
        public BinaryHeap(int size, Order order)
        {
            if (size < 1)
            {
                throw new Exception("二叉堆最少长度2");
            }

            this.Size = size;
            this.Order = order;
            this.Size++;
            Items = new T[this.Size];
            this.length = 0;
        }

        /*
         我们可以举一个例子,假设我们已经有了一个最小二叉堆(其中有7个元素),现在我们要插入一个元素17到这个二叉堆中去,那么插入后二叉堆大小就会加一变成8
         10 30 20 34 38 30 24 17

         现在17位下划线的那个,我们已经将他放在数组的最后位置了,然后我们比较他与他的父节点(位置为8/2 = 4),在位置4(从1开始数)的为34,由于17小于34,所以我们交换彼此,得到下图:
         10 30 20 17 38 30 24 34

         现在17跑到位置4中去了,然后我们比较17和他的新的父节点(位置为4/2 = 2),
         在位置2(从1开始数)的为30,由于17还是小于30,所以交换彼此,得到下图:
         10 17 20 30 38 30 24 34
         现在17跑到第二位了,继续比较,父节点位置为2/2 = 1,由于17不小于10,所以这里就没有必要比较了,走到这一步我们的新元素17添加完成。现在的堆已经添加了元素17,堆中有8位按照最小二叉堆规则排序的元素。
         */

        /// <summary>
        /// 添加节点
        /// </summary>
        /// <param name="item"></param>
        public void Add(T item)
        {
            if (this.length == 0)
            {
                Items[1] = item;
            }
            else
            {
                int len = this.length;
                if (len >= this.Size)
                {
                    throw new Exception("二叉堆已经满了,不能再添加了");
                }

                int endPos = len + 1;
                Items[endPos] = item;

                //从二叉堆最中间的数字 和 最末尾的数字第一次进行比较
                int parentPos = endPos / 2;
                bool isContinue = true;
                while (parentPos != 0 && isContinue)
                {
                    // 升序
                    if (Order == BinaryHeap.Order.ASC)
                    {
                        //实例比参数小就返回 -1
                        if (Items[endPos].CompareTo(Items[parentPos]) < 0)
                        {
                            //交换
                            Swap(ref Items[endPos], ref Items[parentPos]);

                            endPos = parentPos;
                            parentPos = endPos / 2;
                        }
                        else
                        {
                            isContinue = false;
                        }
                    }
                    else
                    {
                        //降序
                        if (Items[endPos].CompareTo(Items[parentPos]) > 0)
                        {
                            Swap(ref Items[endPos], ref Items[parentPos]);

                            endPos = parentPos;
                            parentPos = endPos / 2;
                        }
                        else
                        {
                            isContinue = false;
                        }
                    }
                }
            }

            this.length++;
        }

        /// <summary>
        /// 删除节点
        /// </summary>
        /// <returns>if the order is ASC, return the smallest one, if DESC, return the largest one.</returns>
        public T Remove()
        {
            if (this.length == 0)
            {
                throw new Exception("二叉树为空");
            }
            // 把二叉堆的第一个元素删除掉
            T removedItem = Items[1];
            int len = this.length;
            Items[1] = Items[len];      //把末尾的元素添加到第一位

            // 减少二叉堆的长度
            this.length--;

            //先计算出第一次比较的两个节点
            int currentPos = 1;
            int leftChildPos = currentPos * 2;
            int rightChildPos = currentPos * 2 + 1;

            bool isContinue = true;

            while ((leftChildPos <= len || rightChildPos <= len) && isContinue)
            {
                // Compare the removing item to its childrens, swap each other if needed
                if (Order == BinaryHeap.Order.ASC)
                {
                    #region 升序
                    if (leftChildPos <= len && rightChildPos <= len)
                    {
                        //当左节点小于右节点的时候,当前节点就跟左节点对比(是否交换)
                        if (Items[leftChildPos].CompareTo(Items[rightChildPos]) < 0 && Items[currentPos].CompareTo(Items[leftChildPos]) >= 0)
                        {
                            Swap(ref Items[currentPos], ref Items[leftChildPos]);
                            currentPos = leftChildPos;
                        }
                        //当左节点大于等于右节点的时候,当前节点就跟右节点对比(是否交换)
                        else if (Items[leftChildPos].CompareTo(Items[rightChildPos]) >= 0 && Items[currentPos].CompareTo(Items[rightChildPos]) >= 0)
                        {
                            Swap(ref Items[currentPos], ref Items[rightChildPos]);
                            currentPos = rightChildPos;
                        }
                        else
                        {
                            isContinue = false;
                        }
                    }
                    else if (leftChildPos <= len)           //左节点比较
                    {
                        if (Items[currentPos].CompareTo(Items[leftChildPos]) >= 0)
                        {
                            Swap(ref Items[currentPos], ref Items[leftChildPos]);
                            currentPos = leftChildPos;
                        }
                        else
                        {
                            isContinue = false;
                        }
                    }
                    else if (rightChildPos <= len)           //右节点比较
                    {
                        if (Items[currentPos].CompareTo(Items[rightChildPos]) >= 0)
                        {
                            Swap(ref Items[currentPos], ref Items[rightChildPos]);
                            currentPos = rightChildPos;
                        }
                        else
                        {
                            isContinue = false;
                        }
                    }
                    else
                    {
                        isContinue = false;
                    }
                    #endregion

                    leftChildPos = currentPos * 2;
                    rightChildPos = currentPos * 2 + 1;
                }
                else
                {
                    #region 降序
                    if (leftChildPos <= len && rightChildPos <= len)
                    {
                        if (Items[leftChildPos].CompareTo(Items[rightChildPos]) > 0 && Items[currentPos].CompareTo(Items[leftChildPos]) <= 0)
                        {
                            Swap(ref Items[currentPos], ref Items[leftChildPos]);
                            currentPos = leftChildPos;
                        }
                        else if (Items[leftChildPos].CompareTo(Items[rightChildPos]) <= 0 && Items[currentPos].CompareTo(Items[rightChildPos]) <= 0)
                        {
                            Swap(ref Items[currentPos], ref Items[rightChildPos]);
                            currentPos = rightChildPos;
                        }
                        else
                        {
                            isContinue = false;
                        }
                    }
                    else if (leftChildPos <= len)
                    {
                        if (Items[currentPos].CompareTo(Items[leftChildPos]) <= 0)
                        {
                            Swap(ref Items[currentPos], ref Items[leftChildPos]);
                            currentPos = leftChildPos;
                        }
                        else
                        {
                            isContinue = false;
                        }
                    }
                    else if (rightChildPos <= len)
                    {
                        if (Items[currentPos].CompareTo(Items[rightChildPos]) <= 0)
                        {
                            Swap(ref Items[currentPos], ref Items[rightChildPos]);
                            currentPos = rightChildPos;
                        }
                        else
                        {
                            isContinue = false;
                        }
                    }
                    else
                    {
                        isContinue = false;
                    }
                    #endregion

                    leftChildPos = currentPos * 2;
                    rightChildPos = currentPos * 2 + 1;
                }
            }

            return removedItem;
        }

        /// <summary>
        /// 排序二叉堆
        /// </summary>
        /// <returns>Return the sorted heap array</returns>
        public IEnumerable<T> Sort()
        {
            if (this.length == 0)
            {
                throw new Exception("The heap is empty");
            }

            while (this.length > 0)
            {
                yield return Remove();
            }
        }

        #region Private method
        /// <summary>
        /// Swap each other
        /// </summary>
        /// <param name="t1">The first one</param>
        /// <param name="t2">The second one</param>
        private void Swap(ref T t1, ref T t2)
        {
            T temp = t1;
            t1 = t2;
            t2 = temp;
        }
        #endregion
    }
}
时间: 2024-08-01 20:48:44

C#实现范型二叉堆的相关文章

二叉堆(binary heap)

堆(heap) 亦被称为:优先队列(priority queue),是计算机科学中一类特殊的数据结构的统称.堆通常是一个可以被看做一棵树的数组对象.在队列中,调度程序反复提取队列中第一个作业并运行,因而实际情况中某些时间较短的任务将等待很长时间才能结束,或者某些不短小,但具有重要性的作业,同样应当具有优先权.堆即为解决此类问题设计的一种数据结构. 本文地址:http://www.cnblogs.com/archimedes/p/binary-heap.html,转载请注明源地址. 逻辑定义 n个

算法—二叉堆

实现栈或是队列与实现优先队列的最大不同在于对性能的要求.对于栈和队列,我们的实现能够在常数时间内完成所有操作:而对于优先队列,插入元素和删除最大元素这两个操作之一在最坏情况下需要线性时间来完成.我们接下来要讨论的基于数据结构堆的实现能够保证这两种操作都能更快地执行. 1.堆的定义 数据结构二叉堆能够很好地实现优先队列的基本操作.在二叉堆的数组中,每个元素都要保证大于等于另两个特定位置的元素.相应地,这些位置的元素又至少要大于等于数组中的另两个元素,以此类推.如果我们将所有元素画成一棵二叉树,将每

二叉堆 - 最小堆

二叉堆:一般我们拿来用的就是最大堆和最小堆. 最小堆:每个节点的值比它的左右子节点的值要大. 代码实现如下:参考Mark Allen Weiss<数据结构和算法分析>(第二版) 1 #include <cstdio> 2 #include <cstdlib> 3 4 #define MIN (1<<(sizeof(int)*8-1)) 5 6 typedef int Item; 7 typedef struct HeapStruct* heap; 8 9 s

Bestcoder4——Happy Three Friends(二叉堆)

本文出自:http://blog.csdn.net/svitter Happy Three Friends Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 0    Accepted Submission(s): 0 Problem Description Dong-hao , Grandpa Shawn , Beautful-leg

堆排序:什么是堆?什么是最大堆?二叉堆是什么?堆排序算法是怎么样的?PHP如何实现堆排序?

本文标签:  堆排序 php php算法 堆排序算法 二叉堆 数据结构 REST   服务器 什么是堆 这里的堆(二叉堆),指得不是堆栈的那个堆,而是一种数据结构. 堆可以视为一棵完全的二叉树,完全二叉树的一个"优秀"的性质是,除了最底层之外,每一层都是满的,这使得堆可以利用数组来表示,每一个结点对应数组中的一个元素. 数组与堆之间的关系 二叉堆一般分为两种:最大堆和最小堆. 什么是最大堆 堆中每个父节点的元素值都大于等于其孩子结点(如果存在),这样的堆就是一个最大堆 因此,最大堆中的

poj 3253 初涉二叉堆 模板题

这道题很久以前就做过了 当时是百度学习了优先队列 后来发现其实还有个用sort的办法 就是默认sort排序后 a[i]+=a[i-1] 然后sort(a+i,a+i+n) (大概可以这样...答案忘了...) 嗯...其实标准解法是二叉堆.. 主函数里面的while里面wa了好多次.. 每次都选最小的那俩相加 再放回去 #include<stdio.h> #include<string.h> #include<algorithm> using namespace std

在A*寻路中使用二叉堆

接上篇:A*寻路初探 GameDev.net 在A*寻路中使用二叉堆 作者:Patrick Lester(2003年4月11日更新) 译者:Panic 2005年3月28日 译者序:     这一篇文章,是"A* Pathfinding for Beginners.",也就是我翻译的另一篇文章<A*寻路初探>的补充,在这篇文章里,作者再一次展现了他阐述复杂话题的非凡能力,用通俗易懂的语句清晰的解释了容易让人迷惑的问题.还是那句话,如果你看了这篇文章仍然无法领会作者的意图,那

堆、二叉堆、堆排序

堆.二叉堆.堆排序 堆的概念: n个元素序列 { k1, k2, k3, k4, k5, k6 -. kn } 当且仅当满足以下关系时才会被称为堆: ki <= k2i,ki <= k2i+1 或者 ki >= k2i,ki >= k2i+1 (i = 1,2,3,4 .. n/2) 如果数组的下表是从0开始,那么需要满足 ki <= k2i+1,ki <= k2i+2 或者 ki >= k2i+1,ki >= k2i+2 (i = 0,1,2,3 .. n

AC日记——二叉堆练习3 codevs 3110

3110 二叉堆练习3 时间限制: 3 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解 题目描述 Description 给定N(N≤500,000)和N个整数(较有序),将其排序后输出. 输入描述 Input Description N和N个整数 输出描述 Output Description N个整数(升序) 样例输入 Sample Input 5 12 11 10 8 9 样例输出 Sample Output 8 9 10 11 12 数据范围及提示 Data Si