数据结构中的堆
一:堆排序
堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i]。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。下面附上简单C#简单实现:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Heap { /// <summary> /// 堆排序实现 /// </summary> class HeapSort { public static void Sort<T>(T[] originArr) where T : IComparable { //首先建堆 BuildMaxHeap<T>(originArr); //在一个堆上在进行排序 RealSort<T>(originArr); } private static void RealSort<T>(T[] originArr) where T : IComparable { for (int i = 0; i < originArr.Length-1; i++) { Swap<T>(originArr , 0, originArr.Length - (i+1)); MaxHeapIFY<T>(originArr, originArr.Length - (i + 1), 0); } } /// <summary> /// 1.首先是需要清楚 GetMaxObjInHeap方法的作用,是在一个堆上插入一个值,并保证插入后堆的性质不变 /// 2.堆其实是满足完全二叉树的性质的,也就是 叶子节点 = (总结点+1)/2 或者 总结点 / 2 /// 3.把每个叶子节点看做一个独立的最大堆,自底而上构建最大堆 /// </summary> private static void BuildMaxHeap<T>(T[] originArr) where T : IComparable { int len = originArr.Length / 2; for (int i = len; i >= 0 ; i--) { MaxHeapIFY<T>(originArr,originArr.Length, i); } } /// <summary> /// 堆操作中核心方法,并维护最大堆的性质 /// 假设originList是一个最大堆,实现在堆固定位置插入元素,并同时保证最大堆的性质 /// </summary> private static void MaxHeapIFY<T>(T[] originList, int heapSie, int pos) where T : IComparable { int len = heapSie; int largest = 0; int cLeft = pos * 2; int cRight = pos * 2 + 1; while (cLeft < len || cRight < len) { largest = cLeft; if (cRight < len && originList[cLeft].CompareTo(originList[cRight]) < 0) { largest = cRight; } if (originList[pos].CompareTo(originList[largest]) >= 0) { break; } else { Swap<T>(originList, pos, largest); pos = largest; cLeft = pos * 2; cRight = pos * 2 + 1; } } } /// <summary> /// 数组中两个元素交换 /// </summary> private static void Swap<T>(T[] originList, int posFirst, int posSec) where T : IComparable { T temp = originList[posFirst]; originList[posFirst] = originList[posSec]; originList[posSec] = temp; } public static void PrintArr<T>(T[] arr) { for (int i = 0; i < arr.Length; i++) { Console.Write(arr[i] + " , "); } Console.WriteLine(""); Console.WriteLine("=================="); } } }
二,优先队列
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Heap { /// <summary> /// 优先队列实现 /// </summary> class PriorityQueue<T> where T:IComparable { private List<T> queue; public PriorityQueue(int size = 10) { queue = new List<T>(size); } public PriorityQueue<T> Add(T t) { if (queue.Count <= 0) { queue.Add(t); } else { queue.Add(t); HeapIncreaseKey(t, queue.Count -1, true); } return this; } public T Pop() { if (queue.Count <= 0) return default(T); Swap(queue, 0, queue.Count - 1); MaxHeapIFY(queue, queue.Count - 1, 0); T max = queue[queue.Count - 1]; queue.RemoveAt(queue.Count - 1); return max; } /// <summary> /// 堆操作中核心方法,并维护最大堆的性质 /// 假设originList是一个最大堆,实现在堆固定位置插入元素,并同时保证最大堆的性质 /// </summary> private void MaxHeapIFY(List<T> originList, int heapSie, int pos) { int len = heapSie; int largest = 0; int cLeft = pos * 2; int cRight = pos * 2 + 1; while (cLeft < len || cRight < len) { largest = cLeft; if (cRight < len && originList[cLeft].CompareTo(originList[cRight]) < 0) { largest = cRight; } if (originList[pos].CompareTo(originList[largest]) >= 0) { break; } else { Swap(originList, pos, largest); pos = largest; cLeft = pos * 2; cRight = pos * 2 + 1; } } } private void HeapIncreaseKey(T key, int pos, bool isInsert = false) { if (queue.Count <= 0) return; if (key.CompareTo(queue[pos]) < 0 && !isInsert) return; //赋值 queue[pos] = key; //维护堆性质 int parent = Parent(pos); while (parent >= 0 && queue[pos].CompareTo(queue[parent]) > 0) { Swap(queue, pos, parent); pos = parent; parent = Parent(parent); } } private int Parent(int pos) { return pos / 2; } /// <summary> /// 数组中两个元素交换 /// </summary> private void Swap(List<T> originList, int posFirst, int posSec) { T temp = originList[posFirst]; originList[posFirst] = originList[posSec]; originList[posSec] = temp; } } }