using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Hont
{
public class HeapSort
{
public class Node
{
/// <summary>
/// 用了一下空對象模式,省去了判斷null
/// </summary>
public readonly static Node EMPTY_NODE;
public Node LeftChild { get; set; }
public Node RightChild { get; set; }
public Node Parent { get; set; }
public int Value { get; set; }
public bool IsUsed { get; set; }
static Node()
{
EMPTY_NODE = new Node() { Value = 0, IsUsed = true };
}
public Node()
{
LeftChild = EMPTY_NODE;
RightChild = EMPTY_NODE;
}
public Node(Node parent)
: this()
{
this.Parent = parent;
}
}
/// <summary>
/// 執行排序
/// </summary>
/// <param name="sourceArray">原始數組</param>
/// <param name="maxOrMin">降序還是升序</param>
/// <returns>排序後的數組</returns>
public int[] Sort(int[] sourceArray, bool maxOrMin = true)
{
Func<int, int, bool> compare = null;
if (maxOrMin)
compare = (a, b) => a > b;
else
compare = (a, b) => a < b;
var rootNode = BuildHeap(sourceArray.ToList());
AdjustHeap(rootNode, compare);
SortHeap(rootNode, compare);
return OutputHeap(rootNode).ToArray();
}
/// <summary>
/// 建構堆,因為沒有用數組去實作,需要額外建構
/// </summary>
Node BuildHeap(List<int> sourceList)
{
Node result = new Node();
List<Node> nextDepthNodeList = new List<Node>();
List<Node> tmpNextDepthNodeList = new List<Node>();
BuildHeap(result, sourceList, nextDepthNodeList);
for (int i = 0; i < nextDepthNodeList.Count; i++)
{
var item = nextDepthNodeList[i];
if (!BuildHeap(item, sourceList, tmpNextDepthNodeList))
{
break;
}
if (i - 1 == nextDepthNodeList.Count)
{
nextDepthNodeList = tmpNextDepthNodeList;
tmpNextDepthNodeList.Clear();
i = 0;
}
}
var lastNode = GetLastSortNode(result);
result.Value = lastNode.Value;
if(lastNode.Parent.LeftChild == lastNode)
{
lastNode.Parent.LeftChild = Node.EMPTY_NODE;
}
else
{
lastNode.Parent.RightChild = Node.EMPTY_NODE;
}
return result;
}
bool BuildHeap(Node currentNode, List<int> sourceList, List<Node> nextDepthNodeList)
{
if (sourceList.Count < 1) return false;
var firstNode = sourceList[0];
currentNode.LeftChild = new Node(currentNode) { Value = firstNode };
nextDepthNodeList.Add(currentNode.LeftChild);
sourceList.RemoveAt(0);
if (sourceList.Count > 0)
{
var lastNode = sourceList[sourceList.Count - 1];
currentNode.RightChild = new Node(currentNode) { Value = lastNode };
nextDepthNodeList.Add(currentNode.RightChild);
sourceList.RemoveAt(sourceList.Count - 1);
}
return true;
}
/// <summary>
/// 調整堆,調整至大頂堆或小頂堆,依據第二個參數
/// </summary>
void AdjustHeap(Node heap, Func<int, int, bool> compare)
{
if (heap == Node.EMPTY_NODE) return;
if (heap.LeftChild.IsUsed && heap.RightChild.IsUsed) return;
var leftChild = heap.LeftChild;
var rightChild = heap.RightChild;
var leftChildValue = heap.LeftChild.Value;
var rightChildValue = heap.RightChild.Value;
if (leftChild.IsUsed) leftChildValue = compare(int.MinValue, int.MaxValue) ? int.MaxValue : int.MinValue;
if (rightChild.IsUsed) rightChildValue = compare(int.MinValue, int.MaxValue) ? int.MaxValue : int.MinValue;
var selectChild = compare(leftChildValue, rightChildValue) ? leftChild : rightChild;
var flag = compare(selectChild.Value, heap.Value);
if (flag)
{
var tmp = heap.Value;
heap.Value = selectChild.Value;
selectChild.Value = tmp;
}
AdjustHeap(heap.LeftChild, compare);
AdjustHeap(heap.RightChild, compare);
if (flag)
{
AdjustHeap(heap, compare);
}
}
void SortHeap(Node root, Func<int, int, bool> compare)
{
while (!root.IsUsed)
{
var lastNode = GetLastSortNode(root);
var tmpHeapValue = root.Value;
root.Value = lastNode.Value;
lastNode.Value = tmpHeapValue;
lastNode.IsUsed = true;
AdjustHeap(root, compare);
}
}
/// <summary>
/// 獲得最後可用的堆成員,如果是IsUsed說明是有序區就跳過,主要用于排序時,首尾成員交換
/// </summary>
Node GetLastSortNode(Node root)
{
Node result = root;
while (true)
{
if (result.RightChild != Node.EMPTY_NODE && !result.RightChild.IsUsed)
{
result = result.RightChild;
}
else if (result.LeftChild != Node.EMPTY_NODE && !result.LeftChild.IsUsed)
{
result = result.LeftChild;
}
else
{
break;
}
}
return result;
}
/// <summary>
/// 周遊節點
/// </summary>
void ForeachNode(Node root, Action<Node> foreachContent)
{
if (root != Node.EMPTY_NODE)
{
foreachContent(root);
}
if (root.LeftChild != Node.EMPTY_NODE)
{
ForeachNode(root.LeftChild, foreachContent);
}
if (root.RightChild != Node.EMPTY_NODE)
{
ForeachNode(root.RightChild, foreachContent);
}
}
List<int> OutputHeap(Node root)
{
List<int> result = new List<int>();
ForeachNode(root, m => m.IsUsed = false);
while (!root.IsUsed)
{
var tmpNode = GetLastSortNode(root);
result.Add(tmpNode.Value);
tmpNode.IsUsed = true;
}
return result;
}
}
}
Heap Sort
調用:
堆排序
堆排序
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Hont;
namespace HeapSortPackage
{
class Program
{
static void Main(string[] args)
{
HeapSort heapSort = new HeapSort();
var result = heapSort.Sort(new int[] { 22, 44, 88, 5, 6 }, true);
Console.WriteLine(string.Join(",", result));
Console.Read();
}
}
}