排序算法的实现

1.冒泡排序

顾名思义,冒泡排序就是每次遍历一次数列,将较大的数下s沉,较小的数上浮,然后再重复排序后面剩下的数列,直至排完最后一个数。
时间复杂度:O(n*2)
稳定性:稳定.
代码实现:

void BubbleSort(int* a, size_t n)
{
    for (size_t end = n; end > 0; --end)
    {
        bool exchange = false;//
        for (size_t i = 1; i < end; ++i)
        {
            if (a[i-1] > a[i])
            {
                swap(a[i-1], a[i]);
                exchange = true;
            }
        }

        if (exchange == false)
        {
            break;
        }
    }
}

注:上面加上bool判断,是因为有可能在循环条件结束前就已经排好序了,此时如果排好序了,将不会再发生交换,exchange==false,排序过程结束。

2.选择排序

顾名思义,就是每次在数组中剩余的数中找出最小的数,依次完成排序。
时间复杂度:O(n*2)
稳定性:不稳定

void SelectSort(int* a, size_t n)
{
    assert(a);
    int begin = 0;
    int end = n-1;
    while(begin < end)
    {
        int min=begin, max=begin;
        for (size_t i = begin; i <= end; ++i)
        {
            if (a[i] < a[min])
                min = i;

            if (a[i] > a[max])
                max = i;
        }

        swap(a[max], a[end]);
        // 修正
        if (min == end)
            min = max;

        swap(a[min], a[begin]);
        ++begin;
        --end;
    }
}

3.插入排序

插入排序就类似于插入扑克牌一样,将数字插入到合适的位置。
最优复杂度:当数组有序时,时间复杂度为O(n)
最差复杂度:当数组无序时,时间复杂度为O(n*2)
稳定性:稳定
代码如下:

// 时间复杂度O(N^2) 逆序最坏 顺序最好 最好情况O(N)
void InsertSort(int* a, size_t n)
{
    //[0, end] end+1插入
    for (int i = 0; i < n-1; ++i)
    {
        int end = i;
        int tmp = a[end+1];
        while (end >= 0 && a[end] > tmp)
        {
            a[end+1] = a[end];
            --end;
        }
        a[end+1] = tmp;
    }
}

4.希尔排序

先将序列分成较多个子序列分别进行排序,再分成较少个子序列分别进行排序,直到最后为一个序列排序,相比较简单交换排序算法,先比较相邻的数,而希尔排序可以快速减少大量无序的情况。
时间复杂度:O(nlogn)
稳定性:不稳定
代码如下:

// 相比直接插入排序。顺序情况下不如直接插入。逆序效果最好。
void ShellSort(int* a, size_t n)
{
    int gap = n;
    while (gap > 1) // 3^x = N
    {
        gap = gap/3 + 1;
        for (size_t i = 0; i < n-gap; ++i)
        {
            int end = i;
            int tmp = a[end+gap];
            while (end >= 0 && a[end] > tmp)
            {
                a[end+gap] = a[end];
                end -= gap;
            }
            a[end+gap] = tmp;
        }
    }
}

5.归并排序

归并排序采用“分而治之”的思想,先将整个数组分为两份,两份分为四份,直到每组只有一个元素,然后可以将每组组内元素排序,然后再依次归并回原来的组里,这样就会依次完成排序,归并排序需要开辟一个新的数组。
时间复杂度:O(nlogn)
稳定性:稳定
代码如下:

void _MergeSort(int* a, int left, int right, int* tmp)
{
    if (left >= right)
    {
        return;
    }

    int mid = left + ((right-left)>>1);
    // [left,mid], [mid+1, right]  有序
    _MergeSort(a, left, mid, tmp);
    _MergeSort(a, mid+1, right, tmp);

    int begin1 = left, end1 = mid;
    int begin2 = mid+1, end2 = right;
    size_t index = left;
    while (begin1 <= end1 && begin2 <= end2)
    {
        if (a[begin1] < a[begin2])
            tmp[index++] = a[begin1++];
        else
            tmp[index++] = a[begin2++];
    }

    while (begin1 <= end1)
        tmp[index++] = a[begin1++];

    while (begin2 <= end2)
        tmp[index++] = a[begin2++];

    memcpy(a+left, tmp+left, (right-left+1)*sizeof(int));
}

void MergeSort(int* a, size_t n)
{
    assert(a);
    int* tmp = new int[n];
    _MergeSort(a, 0, n-1, tmp);
    delete[] tmp;
}

6.快速排序

找一个基点,一般都会选择数组第一个数字,第一遍将比该数小的放到左边,比该数大的放在右边,然后递归分别对两边的数进行排序。
时间复杂度:O(nlogn)
稳定性:不稳定
代码如下:

int PartSort2(int* a, int begin, int end)
{
    int key = a[end];
    while (begin < end)
    {
        while (begin < end && a[begin] <= key)
        {
            ++begin;
        }

        a[end] = a[begin]; // 填坑

        while (begin < end && a[end] >= key)
        {
            --end;
        }

        a[begin] = a[end];
    }

    a[begin] = key;
    return begin;
}
void QuickSort(int* a, int left, int right)
{
    if (left >= right)
        return;

    int div = PartSort3(a, left, right);
    // [left, div-1]
    // [div+1, right]

    QuickSort(a, left, div-1);
    QuickSort(a, div+1, right);
}

7.堆排序

堆排序会将所有的数据建立成一个堆,最大的数据在堆顶,将其与堆底最后一个数字交换,接下来重建堆,交换数据,依次下去。
时间复杂度:O(nlogn)
稳定性:不稳定
代码如下:

void AdjustDown(int* a, size_t size, int root)
{
    int parent = root;
    int child = parent*2+1;
    while (child < size)
    {
        if (child+1 < size && a[child+1] > a[child])
        {
            ++child;
        }

        if (a[child] > a[parent])
        {
            swap(a[child], a[parent]);
            parent = child;
            child = parent*2+1;
        }
        else
        {
            break;
        }
    }
}

// O(N*log(N))
void HeapSort(int* a, size_t n)
{
    for(int i = (n-2)/2; i >= 0; --i)
    {
        AdjustDown(a, n, i); // log(N)
    }

    size_t end = n-1;
    while (end > 0)
    {
        swap(a[0], a[end]);
        AdjustDown(a, end, 0);
        --end;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值