常见的排序算法——选择排序

选择排序
基本思想

每一趟在后面 n - i 个待排序的数据元素集合中选择出关键码最小的数据元素,作为有序元素序列的第i个元素。待 到第 n - 2 趟做完,待排序元素集合中只剩下一个元素,排序结束。

直接选择排序
  • 在元素集合array[i]—-array[n-1]中选择关键码最大(小)的数据元素
  • 若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中的最后一个(第一个)元素交换。
  • 在剩余的array[i]—-array[n-2](array[i+1]—-array[n-1])的集合中,重复上述步骤,直到集合剩余1一个元素
代码如下
void Swop(int *a, int *b)
{
    int temp = *a;
    *a = *b;
    *b = temp;
}

void Select(int array[], int size)
{
    int end = size - 1;
    int begin = 0;
    int i = 0;

    //这里i的终止条件必须是size
    //如果是end,就会少排几次
    for ( i = begin; i <= size; ++i)
    {
        int Maxpos = begin;

        for (int j = begin; j <= end; ++j)
        {
            if (array[Maxpos] < array[j])
                Maxpos = j;
        }

        if (Maxpos != end)
            Swop(&array[Maxpos], &array[end]);

        --end;
    }
}

我们可以对其在进行优化,一次遍历找到一个最大的元素,一个最小的元素,这样能节省时间。

void Select_OP(int array[], int size)
{
    int end = size - 1;
    int begin = 0;

    //因为end为size-1,闭区间,所以这里的i要小于等于end
    //终止条件不是size,是因为
    for (int i = begin; i <= end; ++i)
    {
        int Maxpos = begin;
        int Minpos = begin;

        for (int j = begin + 1; j <= end; ++j)
        {
            if (array[Maxpos] < array[j])
                Maxpos = j;
            if (array[Minpos] > array[j])
                Minpos = j;
        }
        if (Maxpos != end)
            Swop(&array[Maxpos], &array[end]);

        //如果最小值在末尾,最小值就会被换走,因此要更新Minpos的值
        if (Minpos == end)
            Minpos = Maxpos;

        if (Minpos != begin)
            Swop(&array[Minpos], &array[begin]);
        --end;
        ++begin;
    }
}
总结
  • 直接选择排序的时间复杂度为O(n^2)
  • 空间复杂度为O(1)
  • 它是一种不稳定的排序算法
  • 缺点是比较次数太多
堆排序

创建堆:升序—>大堆,降序—>小堆

具体步骤:

  • 建堆
  • 把堆顶array[0]元素和当前最堆的最后一个元素交换
  • 堆元素个数减1
  • 由于第1步后根节点不再满足最堆定义,向下调整根结点

这里写图片描述

代码如下:
void AdjustDown(int array[], int size, int parent)
{
    int child = (parent << 1) + 1;

    //这里就是所说的循环条件
    while (child <= size)
    {
        //找到两个孩子中较大的一个
        if (child + 1 <= size && array[child + 1] > array[child])
        {
            child = child + 1;
        }
        //比较parent和孩子的大小
        if (array[parent] < array[child])
        {

            Swop(&array[parent], &array[child]);
            parent = child;
            child = (parent << 1) + 1;
        }
        else
        {
            break;
        }
    }
}

//升序-->将大堆
void HeapSort(int array[], int size)
{
    int root = (size - 2) >> 1;
    int end = size - 1;
    //建堆
    while (root >= 0)
    {
        AdjustDown(array, size, root);
        root--;
    }

    //排序
    while (end >= 0)
    {
        //交换根节点和最后一个元素
        Swop(&array[end], &array[0]);


        //这里的end--和向下调整的顺序,取决于向下调整里的循环条件
        //如果是闭区间,则end需要在前边,如果是开区间,则end在后边

        //最后一个元素已经排好,因此下次调整堆,不应包括此节点
        end--;

        //不满足大堆性质,调整
        AdjustDown(array, end, 0);
    }
}
总结
  • 把一棵完全二叉树调整为堆,以及每次将堆顶元素交换后
    进行调整的时间复杂度均为O( lgn),所以堆排序的时间复杂度为:O(nlgn )
  • 空间复杂度为O(1)
  • 堆排序是一种不稳定的排序算法
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值