数据结构6-排序算法(直接插入排序、希尔排序、快速排序、归并排序和堆排序)

        所有排序中,需要排序的数组array的第0位不存放有效的数字,而是作为哨兵存在。

1.直接插入排序

        直接插入排序的基本操作是将一个记录插入到已排好序的表中,从而得到一个新的、记录增1的有序表。一个无序的数字array(同时可以把它当做一个长度为1的有序表),从1以后的每个位置都希望找到自己合适的位置插入,第i位(i从2开始)数字要到自己位置插入,那么就需要从前i-1位开始依次比较(比前一位大,比后一位小),同时后移记录。直到有序表的长度为数组array的长度。

/// <summary>
/// 插入排序
/// </summary>
public void InsertSort(int[] array)
{
    int i = 0, j = 0;

    for (i = 2; i < array.Length; i++)
    {
        if (array[i] < array[i - 1])
        {
            array[0] = array[i];
            array[i] = array[i - 1];
            for (j = i - 2; array[0] < array[j]; j--)
            {
                array[j + 1] = array[j];
            }
            array[j + 1] = array[0];
        }
    }
}
        直接插入排序适合给本来就较为有序的数组做排序,因为数组越有序,插入的次数就越少。时间复杂度为O(n^2)。


2.希尔排序

        希尔排序是直接插入排序的一个改良版。它的思想是:先将整个待排记录序列分割成为若干子序列分别进行直接插入排序,待整个序列“基本有序”时,再对全体记录进行一次直接插入排序。

/// <summary>
/// 希尔排序
/// </summary>
/// <param name="array"></param>
public void ShellSort(int[] array)
{
    int[] dlta = new[] {5, 3, 1};

    for (int i = 0; i < dlta.Length; i++)
    {
        ShellInsert(array, dlta[i]);
    }
}

private void ShellInsert(int[] array, int dk)
{
    int i = 0, j = 0;

    for (i = dk + 1; i < array.Length; i++)
    {
        if (array[i] < array[i - dk])
        {
            array[0] = array[i];
            for (j = i - dk; j > 0 && array[0] < array[j]; j -= dk)
            {
                array[j + dk] = array[j];
            }
            array[j + dk] = array[0];
        }
    }
}

3.快速排序

        快速排序是冒泡排序的一种改进版。它的基本思想是,通过一趟排序将带排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,已达到整个序列有序。

/// <summary>
/// 快速排序
/// </summary>
/// <param name="array"></param>
public void QuickSort(int[] array)
{
    QSort(array, 1, array.Length - 1);
}

private void QSort(int[] array, int low, int high)
{
    if (low < high)
    {
        int pivokey = Partition(array, low, high);
        QSort(array, low, pivokey - 1);
        QSort(array, pivokey + 1, high);
    }
}

private int Partition(int[] array, int low, int high)
{
    array[0] = array[low];
    int pivokey = array[low];
    while (low < high)
    {
        while (low < high && array[high] >= pivokey) high--;
        array[low] = array[high];
        while (low < high && array[low] <= pivokey) low++;
        array[high] = array[low];
    }
    array[low] = pivokey;
    return low;
}
        快速排序适合比较“乱”的序列,若序列已经有序,则快速排序会非常的慢。时间复杂度O(nlogn)。


4.归并排序

        归并排序的思想是,把初始的序列表的每一个关键字都视为一个序列表,然后将相邻两序列表合并成一个序列表并排序,多次合并后最终达到只剩一个表。

/// <summary>
/// 归并排序
/// </summary>
/// <param name="array"></param>
public void MergeSort(int[] array)
{
    //归并排序
    for (int i = 1; i < array.Length; i *= 2)
    {
        MergePass(array, i);
    }
}

private void Merge(int[] array, int low, int mid, int high)
{
    int i = low;
    int j = mid + 1;
    int k = 0;
    int[] array2 = new int[high - low + 1];

    while (i <= mid && j <= high)
    {
        if (array[i] <= array[j])
        {
            array2[k] = array[i];
            i++;
            k++;
        }
        else
        {
            array2[k] = array[j];
            j++;
            k++;
        }
    }

    while (i <= mid)
    {
        array2[k] = array[i];
        k++;
        i++;
    }

    while (j <= high)
    {
        array2[k] = array[j];
        k++;
        j++;
    }

    for (k = 0, i = low; i < high; k++, i++)
    {
        array[i] = array2[k];
    }
}

private void MergePass(int[] array, int gap)
{
    int i =0;
    for (i = 0; i + 2*gap - 1 < array.Length; i += 2*gap)
    {
        Merge(array, i, i + gap - 1, i + 2*gap - 1);
    }
    if (i + gap - 1 < array.Length)
    {
        Merge(array, i, i + gap - 1, array.Length - 1);
    }
}

        归并排序是一种非常稳定的排序,在多数情况下排序时间都可以稳定到一个小的范围内。时间复杂度O(nlogn)。


5.堆排序

        当序列满足Ki >= K(2i) && Ki >= K(2i+1)时,这个序列就是大顶堆,简单的说就是制造出一个二叉树,其根节点大于两子节点。堆排序就需要制造出这些大顶堆,则堆顶的就是最大的数,我们把堆顶移到序列末尾,再重新制造大顶堆,重复之前的步骤。

/// <summary>
/// 堆排序
/// </summary>
/// <param name="array"></param>
public void HeapSort(int[] array)
{
    for (int i = array.Length/2; i >= 1; i--)                //非叶子节点的最大角标为Lenth/2
    {
        HeapAdjust(array, i, array.Length - 1);
    }
    for (int i = array.Length - 1; i > 1; i--)
    {
        int temp = array[1];
        array[1] = array[i];
        array[i] = temp;

        HeapAdjust(array, 1, i - 1);
    }
}

private void HeapAdjust(int[] array, int s, int m)
{
    int tmp = array[s];
    for (int j = 2*s; j <= m; j *= 2)
    {
        if (j < m && array[j] < array[j + 1]) j++;
        if (tmp < array[j])
        {
            array[s] = array[j];
            s = j;
        }
                    
        else
            break;
    }
    array[s] = tmp;
}
        堆排序不适合对记录较少的文件做排序,但很适合对较大的文件排序。时间复杂度O(nlogn)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值