using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace heap
{
    /// 
    /// 堆排序主要使用了自底向上的方法进行了排序
    /// 
    /// 
    public class HEAP
    {
        /// 
        /// 关联数组,数组0位置不可访问
        /// 
        private List listarray;

        /// 
        /// 相关数据结构的比较大小的方法,比较方法的委托,要求第一个值不小于第二个的值的时候返回ture
        /// 
        private Funcbool> comparison;

        //private int heaptreeheight;

        public int COUNT {
            get { return listarray.Count - 1; }
        }

        public int TREEHEIGHT {
            get { return (int)Math.Log(listarray.Count - 1, 2) + 1; }
        }

        private int status;
        /// 
        /// 返回当前堆状态,0为无序堆,1为最大堆,2为最小堆
        /// 
        public int STATUS {
            get { return status; }
        }
        /// 
        /// 初始化堆
        /// 
        /// 关联数组
        /// 相应数据结构的比较方法
        public void InitHeap(List L, Funcbool> compar)
        {
            listarray = new List();
            
            listarray.Add(L[0]);
            listarray.AddRange(L);
            comparison = compar;

            status = 0;
        }

        /// 
        /// 生成最大堆
        /// 
        public void SORTHEAPMAX()
        {
            status = 1;
            for (int i = (int)COUNT / 2; i >= 1; i--)
            {
                MAX_HEAPIFY(i);
            }

        }

        /// 
        /// 生成最小堆
        /// 
        public void SORTHEAPMIN()
        {
            status = 2;
            for (int i = (int)COUNT / 2; i >= 1; i--)
            {
                MIN_HEAPIFY(i);
            }
        }

        /// 
        /// 堆中数据元素交换位置,将值较大的元素放到上面
        /// 
        /// 起始位置
        private void MAX_HEAPIFY(int start)
        {
            int l = left(start);
            int r = right(start);
            int largest = start;
            if (l <= COUNT && comparemor(listarray[l], listarray[largest]))
            {
                largest = l;
            }
            
            if (r <= COUNT && comparemor(listarray[r], listarray[largest]))
            {
                largest = r;
            }           

            if (largest != start)
            {
                exchange(largest, start);
                MAX_HEAPIFY(largest);
            }
        }

        /// 
        /// 堆中数据元素交换位置,将值较小的元素放到上面
        /// 
        /// 起始位置
        private void MIN_HEAPIFY(int start)
        {
            int l = left(start);
            int r = right(start);
            int largest = start;
            if (l <= COUNT && comparemor(listarray[largest], listarray[l]))
            {
                largest = l;
            }

            if (r <= COUNT && comparemor(listarray[largest], listarray[r]))
            {
                largest = r;
            }

            if (largest != start)
            {
                exchange(largest, start);
                MIN_HEAPIFY(largest);
            }
        }

        /// 
        /// 比较两个数据结构,并返回自定义值更大的那个
        /// 
        /// 堆内数据结构
        /// 第一个比较值
        /// 第二个比较值
        /// 比较方法的委托,要求第一个值不小于第二个的值的时候返回ture
        /// 当第一个值大于等于第二个值的时候返回true,当第一个值小于第二个值的时候返回false
        private bool comparemor(T T1,T T2)
        {
            bool result = comparison(T1, T2);
            if (result)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// 
        /// 比较两个数据结构,并返回自定义值更小的那个
        /// 
        /// 堆内数据结构
        /// 第一个比较值
        /// 第二个比较值
        /// 比较方法的委托,要求第一个值不小于第二个的值的时候返回ture
        /// 返回较小值
        private T compareles(T T1, T T2)
        {
            bool result = comparison(T1, T2);
            if (result)
            {
                return T2;
            }
            else
            {
                return T1;
            }
        }

        /// 
        /// 交换两个数据结构位置
        /// 
        /// 
        /// 
        private void exchange(int pos1,int pos2)
        {
            T temp = listarray[pos1];
            listarray[pos1] = listarray[pos2];
            listarray[pos2] = temp;
        }

        //获取该节点的左孩子
        private int left(int i)
        {
            return 2 * i;
        }
        //获取该节点的右孩子
        private int right(int i)
        {
            return 2 * i + 1;
        }
        //获取该节点的父节点
        private int parent(int i)
        {
            if (i != 1)
            {
                return (int)i / 2;
            }
            else
            {
                return 1;
            }
        }

        /// 
        /// 除最后一个元素外,剩下元素最大堆或最小堆的状态下,将最后一个元素插入相应位置
        /// 
        private void havesorttorightpos()
        {
            if (status == 1)//最大堆
            {
                int p = (int)(COUNT / 2);
                int nowpos = COUNT;
                bool flag = true;

                while (flag)
                {
                    if (comparemor(listarray[nowpos], listarray[p]))
                    {
                        exchange(nowpos, p);
                        nowpos = p;
                        p = (int)(nowpos / 2);
                    }
                    else
                    {
                        flag = false;
                        break;
                    }
                }

            }
            else if (status == 2)//最小堆
            {
                int p = (int)(COUNT / 2);
                int nowpos = COUNT;
                bool flag = true;

                while (flag)
                {
                    if (comparemor(listarray[p],listarray[nowpos]))
                    {
                        exchange(nowpos, p);
                        nowpos = p;
                        p = (int)(nowpos / 2);
                    }
                    else
                    {
                        flag = false;
                        break;
                    }
                }
            }
            else
            {

            }
        }

        /// 
        /// 向堆内添加元素并保持堆的原有性质
        /// 
        /// 添加的对象
        public void add(T additem)
        {
            listarray.Add(additem);
            havesorttorightpos();
        }
        /// 
        /// 获取堆顶
        /// 
        /// 
        public T gethead()
        {
            return listarray[1];
        }

        /// 
        /// 出堆
        /// 
        /// 
        public T outhead()
        {
            exchange(1, COUNT);
            T temp = listarray[COUNT];
            listarray.Remove(listarray[COUNT]);


            if (status == 1)//最大堆
            {
                MAX_HEAPIFY(1);
            }
            else if (status == 2)
            {
                MIN_HEAPIFY(1);
            }
            else
            {

            }

            return temp;
        }

        public List getall()
        {
            List temp = new List();
            for (int i = 1; i <= COUNT; i++)
            {
                temp.Add(listarray[i]);
            }
            return temp;
        }
    }
}
C