堆排序

本文详细介绍了堆排序算法的工作原理,包括如何构建大根堆、如何进行堆排序迭代以及C#代码实现。堆排序的时间复杂度为O(nlog2n),通过比较和交换元素来保证排序的正确性。示例代码展示了如何使用堆排序对一组整数进行排序,最终得到升序排列的结果。
摘要由CSDN通过智能技术生成

/*

  • 堆排序是一种选择排序,时间复杂度为O(nlog2n)。
  • 堆排序的特点是:
  • 在排序过程中,将待排序数组看成是一棵完全二叉树的顺序存储结构,
  • 利用完全二叉树中父结点和子结点之间的内在关系,在当前无序区中选择关键字最大(或最小)的记录。
  • 基本思想
  • 1.将待排序数组调整为一个大根堆。大根堆的堆顶元素就是这个堆中最大的元素。
  • 2.将大根堆的堆顶元素和无序区最后一个元素交换,并将无序区最后一个位置列入有序区,然后将新的无序区调整为大根堆。
  • 3.重复操作,直到无序区消失为止。
  • 初始时,整个数组为无序区。每一次交换,都是将大根堆的堆顶元素换入有序区,以保证有序区是有序的。
    */

namespace HeapSort
{
using System;

/// <summary>
/// The program.
/// </summary>
public static class Program
{
    /// <summary>
    /// 程序入口点。
    /// </summary>
    public static void Main()
    {
        int[] a = {1, 14, 6, 2, 8, 66, 9, 3, 0, 10, 5, 34, 76, 809, 4, 7};

        Console.WriteLine("Before Heap Sort:");
        foreach (int i in a)
        {
            Console.Write(i + " ");
        }

        Console.WriteLine("\r\n");

        Console.WriteLine("In Heap Sort:");
        HeapSort(a);
        Console.WriteLine("");

        Console.WriteLine("After Heap Sort:");
        foreach (int i in a)
        {
            Console.Write(i + " ");
        }
    }

    /// <summary>
    /// 堆排序方法。
    /// </summary>
    /// <param name="a">
    /// 待排序数组。
    /// </param>
    private static void HeapSort(int[] a)
    {
        // 建立大根堆。
        BuildMaxHeap(a);
        Console.WriteLine("Build max heap:");
        foreach (int i in a)
        {
            // 打印大根堆。
            Console.Write(i + " ");
        }

        Console.WriteLine("\r\nMax heap in each heap sort iteration:");
        for (int i = a.Length - 1; i > 0; i--)
        {
            // 将堆顶元素和无序区的最后一个元素交换。
            Swap(ref a[0], ref a[i]);

            // 将新的无序区调整为大根堆。
            MaxHeaping(a, 0, i);

            // 打印每一次堆排序迭代后的大根堆。
            for (int j = 0; j < i; j++)
            {
                Console.Write(a[j] + " ");
            }

            Console.WriteLine(string.Empty);
        }
    }

    /// <summary>
    /// 由底向上建堆。
    /// 由完全二叉树的性质可知,叶子结点是从index=a.Length/2开始,
    /// 所以从index=(a.Length/2)-1结点开始由底向上进行大根堆的调整。
    /// </summary>
    /// <param name="a">
    /// 待排序数组。
    /// </param>
    private static void BuildMaxHeap(int[] a)
    {
        for (int i = (a.Length / 2) - 1; i >= 0; i--)
        {
            MaxHeaping(a, i, a.Length);
        }
    }

    /// <summary>
    /// 将指定的结点调整为堆。
    /// </summary>
    /// <param name="a">
    /// 待排序数组。
    /// </param>
    /// <param name="i">
    /// 需要调整的结点。
    /// </param>
    /// <param name="heapSize">
    /// 堆的大小,也指数组中无序区的长度。
    /// </param>
    private static void MaxHeaping(int[] a, int i, int heapSize)
    {
        // 左子结点。
        int left = (2 * i) + 1;

        // 右子结点。
        int right = 2 * (i + 1);

        // 临时变量,存放大的结点值。
        int large = i;

        // 比较左子结点。
        if (left < heapSize && a[left] > a[large])
        {
            large = left;
        }

        // 比较右子结点。
        if (right < heapSize && a[right] > a[large])
        {
            large = right;
        }

        // 如有子结点大于自身就交换,使大的元素上移;并且把该大的元素调整为堆以保证堆的性质。
        if (i != large)
        {
            Swap(ref a[i], ref a[large]);
            MaxHeaping(a, large, heapSize);
        }
    }

    /// <summary>
    /// 交换两个整数的值。
    /// </summary>
    /// <param name="a">整数a。</param>
    /// <param name="b">整数b。</param>
    private static void Swap(ref int a, ref int b)
    {
        int tmp = a;
        a = b;
        b = tmp;
    }
}

}

// Output:
/*
Before Heap Sort:
1 14 6 2 8 66 9 3 0 10 5 34 76 809 4 7
In Heap Sort:
Build max heap:
809 14 76 7 10 66 9 3 0 8 5 34 1 6 4 2
Max heap in each heap sort iteration:
76 14 66 7 10 34 9 3 0 8 5 2 1 6 4
66 14 34 7 10 4 9 3 0 8 5 2 1 6
34 14 9 7 10 4 6 3 0 8 5 2 1
14 10 9 7 8 4 6 3 0 1 5 2
10 8 9 7 5 4 6 3 0 1 2
9 8 6 7 5 4 2 3 0 1
8 7 6 3 5 4 2 1 0
7 5 6 3 0 4 2 1
6 5 4 3 0 1 2
5 3 4 2 0 1
4 3 1 2 0
3 2 1 0
2 0 1
1 0
0
After Heap Sort:
0 1 2 3 4 5 6 7 8 9 10 14 34 66 76 809

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值