算法回顾(一):排序算法(下)

算法回顾(一):排序算法(下)

快速排序

快速排序于1962年提出,其基本思想为:将数组x通过一个数t划分为两部分,使得左边部分的子数组x[l…t-1] < t,右边部分的子数组x[t+1…h] >= t,然后使用分治策略,分别对左右的子数组进行递归排序。
代码如下:

void qsort1(int *x, int len, int l, int h)
{
    if (l >= h)
    {
        return;
    }
    int p = l;
    int i;
    for (i = l+1; i <= h; i++)
    {
        if (x[i] < x[l])
        {
            Swap(x, i, ++p);
        }
    }
    Swap(x, l, p);
    qsort1(x, len, l, p-1);
    qsort1(x, len, p+1, h);
}

qsort1函数可以快速完成对随机数组进行排序,但是对于非随机的数组效果就不一定好了。最极端的情况下,n个相同元素的数组,在这个数组中,插入排序的效果非常好,时间为O(n);但是快速排序的效果就非常差,耗时O(n2)。所以将快速排序进行修改,使用两个指针,虽然提高了交换次数,但是避免了最坏情况。代码如下:

void qsort2(int *x, int len, int l, int h)
{
    if (l >= h)
    {
        return ;
    }
    int t = x[l];
    int i = l;
    int j = h+1;
    while(1)
    {
        // 找到从左到右第一个大于t的位置
        do
        {
            i++;
        }while(i <= h && x[i] < t);
        // 找到从右到左第一个小于t的位置
        do
        {
            j--;
        }while(j >= l && x[j] > t);
        if (i > j)
        {
            break;
        }
        Swap(x, i, j);
    }
    Swap(x, l, j);
    qsort2(x, len, l, j-1);
    qsort2(x, len, j+1, h);
}

堆排序

堆排序是利用堆这种数据结构进行排序。堆是一个完全二叉树,且满足堆的性质(最大堆:父节点的值大于或字节点,最小堆:父节点小于字子节点)。利用堆进行排序,需要实现:堆的创建和堆的调整,简单的算法步骤如下:

  1. 从数组x[0…n]中建立一个最大堆(此时数组的最大值位于x[0])
  2. 将x[0]和x[n]进行交换
  3. 调整堆,使数组x[0…(n-1)]为最大堆,将x[0]和x[n-1]进行交换,循环进行
    代码如下:
//调整堆
void Heapify(int *x, int len, int k)
{
    int lc = k*2 + 1;
    int rc = k*2 + 2;
    int maxk = k;

    if (lc < len && x[lc] > x[maxk])
    {
        maxk = lc;
    }
    if (rc < len && x[rc] > x[maxk])
    {
        maxk = rc;
    }
    if (maxk != k)
    {
        Swap(x, k, maxk);
        Heapify(x, len, maxk);
    }
}
//创建堆
void BuildMaxHeap(int *x, int len)
{
    int i = len/2 - 1;
    for (; i >= 0; i--)
    {
        Heapify(x, len, i);
    }
}
//堆排序
void HeapSort(int *x, int len)
{
    int i;
    BuildMaxHeap(x, len);
    for (i = len-1; i >= 0; i--)
    {
        Swap(x, 0, i);
        Heapify(x, i, 0);
    }

}

计数排序

计数排序与之前的算法相比较思路不同,计数排序不是使用基于比较的排序方法,而是通过记录数组中每个数出现的次数,然后按照每个数在数轴上出现的先后顺序在输出出来。这个比较算法的优势是线性的排序时间,但是缺点是需要额外开辟内存空间,且该内存空间中有很多位置没有被使用到。
代码如下:

void CountSort(int *x, int len)
{
    int maxv = 0;
    int i = 0, j = 0;
    for (i = 0; i < len; i++)
    {
        if (x[i] > maxv)
        {
            maxv = x[i];
        }
    }
    maxv++;
    int *cx = new int[maxv];
    for (i = 0; i<maxv; i++)
    {
        cx[i] = 0;
    }

    for (i = 0; i < len; i++)
    {
        cx[x[i]]++;
    }
    for (i = 0; i < maxv; i++)
    {
        cout<<cx[i]<<" ";
        while (cx[i] > 0)
        {
            x[j++] = i;
            cx[i]--;
        }
    }
    delete []cx;
    cx = NULL;
    cout<<endl;
}

桶排序

桶排序可以说是计数排序的升级版,他将数据分别映射到不同的桶中。与计数排序相比,计数排序其实也是一个个桶,但是这个桶的数目太多,从最小值到最大值。而桶排序则减少桶的数量,通过映射算法将数据分到各个桶中,但是要保证前面的桶的所有数据都比后面桶中的数据都小。
本次代码中的映射算法是使用数的百位和十位。
代码如下:

void BucketSort(int *x, int len)
{
    int i, j, m=0 ;
    int buckets[20][31] = {0}; //多一位,记录每个桶中已经放了多少数据

    for (i = 0; i < len; i++)
    {
        int tmp = x[i]/10;
        buckets[tmp][buckets[tmp][30]++] = x[i];
    }
    for (i = 0; i < 20; i++)
    {
        if (buckets[i][30] != 0)
        {
            BubbleSort(buckets[i], buckets[i][30]);
        }
    }
    for (i = 0; i < 20; i++)
    {
        for (j = 0; j<buckets[i][30]; j++)
        {
            x[m++] = buckets[i][j];
        }
    }
}

基数排序

基数排序的简单思路为:首先使用数据的个位进行排序,然后使用十位进行排序,位次逐渐增高知道所有数的最高位,最后数据就变得有序了。
代码如下:

void RedixSort(int *x, int len)
{
    int maxv = 0;
    int i,j,k,m;
    int num = 0;
    int mod = 1;
    int buckets[10][31] = {0};
    for (i = 0; i<len; i++)
    {
        if (x[i] > maxv)
        {
            maxv = x[i];
        }
    }
    while(maxv > 0)
    {
        num++;
        maxv /= 10;
    }
    for (k = 0; k < num; k++)
    {
        m=0;
        for (i = 0; i < len; i++)
        {
            int tmp = (x[i]/Power(10,k))%10;
            buckets[tmp][buckets[tmp][30]++] = x[i];
        }
        for (i=0; i<10; i++)
        {
            for (j=0; j<buckets[i][30]; j++)
            {
                x[m++] = buckets[i][j];
            }
        }
        memset(buckets, 0, sizeof(buckets));
    }
}

至此,一些常见的排序算法就回顾完了。

参考: 十大经典排序算法(动图演示)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值