//最小堆
class Dui
{
public int[] datas;
public Dui(int maxLength) {
if (maxLength <= 0)
{
datas = new int[16 + 1];
}
else {
datas = new int[maxLength + 1];
}
}
public int Pop() {
int temp = datas[1];
datas[1] = datas[datas[0]];
datas[0]--;
SiftDown(1);
return temp;
}
public bool isEmpty() {
return datas[0] == 0 ? true:false;
}
public void ValueTo(int[] copyValues) {
datas[0] = copyValues.Length;
if (datas[0] < 1) {
return;
}
for (int i = 1; i <= datas[0]; i++) {
datas[i] = copyValues[i-1];
}
Create();//调整节点
}
public void Create() {
//倒数最后一个非叶节点
int index = datas[0] / 2;
for (int i = index; i >= 1; i--) {
SiftDown(i);
}
}
//向下调整
public void SiftDown(int index) {
bool isNeedSwap = true;
int t = index;
//有左儿子
while (index * 2 <= datas[0] && isNeedSwap) {
if (datas[index] > datas[index * 2]) {
t = index * 2;
}
//有右儿子
if (index * 2 + 1 <= datas[0]) {
if (datas[t] > datas[index * 2 + 1]) {
t = index * 2 + 1;
}
}
if (index != t)
{
int temp = datas[index];
datas[index] = datas[t];
datas[t] = temp;
index = t;
}
else {
//比左右两儿子都小了
isNeedSwap = false;
}
}
}
}
static void Main(string[] args)
{
int[] datas = new int[100000];
Random random = new Random();
for (int i = 0; i < 100000; i++) {
datas[i] = random.Next(1, 10000);
}
Stopwatch stopwatch = new Stopwatch();
Dui dui = new Dui(100000);
dui.ValueTo(datas);
stopwatch.Start();
int j = 0;
while (!dui.isEmpty()) {
datas[j++] = dui.Pop();
}
stopwatch.Stop();
for (j = 0; j < 100000; j++) {
Console.WriteLine(datas[j]);
}
Console.WriteLine("用时:" + stopwatch.ElapsedMilliseconds);
Console.ReadKey();
}堆排序,就是利用最小堆,每次都能确定根节点的值就是当前集合中的最小值,所以每次只要将根节点输出,然后将最后一个节点替换上来再向下调整,形成新的最小堆。输出完毕,就是排序完毕了。
还有一种思路就是利用最大堆,根节点为当前集合的最大值,与最后一个节点交换,树长度减1.再向下调整,形成新的最大堆,再和最后一个元素交换....到最后树的长度只有1时,你把树的长度恢复,你会发现这是一个工整的最小堆,按数组顺序输出就是排序好的了。
模拟排序10W条随机数据用时:58ms