排序【2】选择排序

选择排序

算法思想:以升序为例,在整个区间中找出排序码最小的元素,如果这个元素不是这组序列中的第一个元素,那么将它和第一个元素进行交换,使得最小的元素就在第一个位置,然后缩小区间,循环执行上述操作,只到区间中只剩下一个元素。
具体步骤(升序)

  1. 在区间中找到关键码最小的元素。
  2. 如果不是待排序区间的第一个元素,则和带排序区间第一个元素交换。
  3. 缩小待排序区间。这里写图片描述
    代码实现:
void ChangeSort(int *array, int size)
{
    assert(array);
    for (int i = 1; i < size; ++i)
    {
        int minindex = i;//未排序的最小元素下标
        int start = i - 1;//未排序区间第一个元素下标
        while (minindex<size)
        {
            if (array[minindex] < array[start])
                swap(array[minindex], array[start]);
            ++minindex;
        }

    }
}

算法性能
时间复杂度:最好的情况是已经有序,交换次数为0,最坏的情况是逆序,交换次数是n-1,比较次数与关键字的初始状态无关。总的比较次数为N=n*(n-1)/2,所以时间复杂度为O(N^2)
空间复杂度:O(1)
稳定性:不稳定


堆排序

基本思想:堆排序就是利用堆这种数据结构实现的一种排序算法,堆是完全二叉树的一种。堆的特点是:

  1. 最大堆:每一个父节点的值都大于两个子节点
  2. 最小堆:每一个父节点的值都小于两个子节点
    堆排序的基本思想就是利用了这种结构,如果我们需要升序:
    1.把所有[a1,a2,a3…an]建成大堆。
    2.把堆顶的元素(即数组中最大的元素和堆中最后一个元素交换),此时分为两个区域,一个[a1,a2,an–1]无序区和[an]有序区。
    3.因为交换了元素,有可能会违反了堆的性质,因此无序区的元素进行调整,满足堆的性质。
    4.重复步骤2,直到有序区的元素有n-1个。
    这里写图片描述
    代码实现:
void AdJustDown(int *array, int size, int n)
{
    int parent = n;
    int child = parent*+1;
    while (child<n)
    {
        if ((child + 1 < size) && array[child] < array[child + 1])
        {
            ++child;
        }
        if (array[child] > array[parent])
        {
            swap(array[child], array[parent]);
            parent = child;
            child = parent * 2 + 1;
        }
        else
        {

            break;
        }
    }
}
void HeapSort(int *array, int size)
{
    assert(array);
    for (int i=(size-2)>>1;i>=0;++i)
    {
        AdJustDown(array,size,i);//创建大堆,将所有数据都重新排序
    }
    for (int i = size - 1; i >= 0; ++i)
    {
        swap(array[0], array[size]);//交换堆顶元素和已序序列第一个元素
        AdJustDown(array, i, 0);//缩小区间,调整堆结构
    }

}

算法性能

  1. 时间复杂度:因为堆中元素的个数是N,所以堆的高度是logN,那么比较次数就是2logN,交换的次数是N次,所以平均时间复杂度是O(NlogN)
  2. 空间复杂度:O(1)
  3. 稳定性:不稳定

验证结果:
这里写图片描述

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页