排序算法讲解(二)

三、快速排序

快速排序是目前在实际工作当中使用频率最高、效率也最好的一种排序算法。它的主要思想是:有待排序数组S={d1,d2,d3,……,dn},从中挑选一个元素dx最为一个基准,将剩余的元素中小于或者等于dx的元素全都移到dx的前面,将大于dx的元素全部移到dx的后面。这样S课分为两个子集S1和S2,其中S1中的元素全部小于等于dx,S2中的元素全部大于dx。此时一趟排序完成。再遵循以上的思路,用递归的方法,对S1和S2也进行相同的操作。当所有的子序列都只含有一个或者零个元素的时候,说明排序已经完成。

在具体的代码实现过程中。快速排序的每一次递归执行都有两个主要的操作:数据交换和返回基准数dx的追中位置。

举一个具体的例子,假设有待排序数组S = {2,9,3,7,10,1,5,4,6,8},我们设置变量p和r表示数组的首尾元素小标。选取最后一个元素8作为第一次排序的基准数,记为S(r)。剩下的就是将S(p),S(p+1),S(p+2)……S(r-1)进行划分。首先,我们设置变量i = p-1,即第一个元素的前方位置。设置变量j = p,反复执行如下步骤:

(1)j+1,如果S(j)<=S(r),交换S(i+1)和S(j)的位置,然后 i++,j++;若S(j)>S(r),则保持两个元素原位置不变,i值不变,j++。

(2)等到j = r-1的时候,停止步骤(1)。

(3)当上述步骤停止之后,交换S(r)与S(j+1)的值,基准值S(r)就放在了应在的位置上。这样,S(r)之前的元素全部小于等于S(r),S(r)之后的元素全部大于S(r)。


代码:其中,i,j,p,r等字母的含义如上所述。

#include<iostream>
using namespace std;

void Swap(int* a,int* b)
{
    int temp;
    temp = *a;
    *a = *b;
    *b = temp;
}

int Partition(int a[],int p,int r)
{
    int pos;
    int temp = a[r];
    int i = p-1;
    for(int j=p;j<r;j++)
    {
        if(a[j]<=temp)
        {
            i++;
            Swap(&a[i],&a[j]);
        }
    }

    Swap(&a[i+1],&a[r]);
    return i+1;
}

void quickSort(int a[],int p,int r)
{
    int pos = 0;
    if(p<r)
    {
        pos = Partition(a,p,r);
        quickSort(a,p,pos-1);
        quickSort(a,pos+1,r);
    }
}

四、归并排序

归并是指将两个或者多个有序序列合并成为一个有序的序列。如果是将两个有序序列归并成为一个有序序列,那么称之为二路归并。同理,如果是三个并成一个,为三路归并;4个归并成一个,为四路归并……。这里只介绍最简单的二路归并。

归并算法的关键操作是:合并两个已排序的自数据集。其过程可以描述为:我们选取两个数组A和B,声明另外一个数组C长度是A和B的长度之和。我们要做的就是把A和B归并为一个有序数组C。首先,设置3个指针AStr,BStr,CStr分别指向数组A,B,C。AStr和BStr用于比较A和B数组当中的数组的大小。CStr永远指向C数组中需要插入的元素的位置。初始状态下,AStr和BStr分别指向数组A和B的第一个元素,然后比较这两个元素的大小,将较小的元素插入到C数组中的CStr指针所指向的位置。接着,将刚挪到C数组的元素所在的数组的指针往后移……以此类推,直到某一个数组所有的元素都被处理了。此时,将另一个数组的剩余元素复制到C数组的末尾即可。


代码:

#include<iostream>
using namespace std;
///首先是两个数组的合并操作.
void Merge(int a[],int b[],int c[],int lenA,int lenB)///将数组a,b合并为c数组,a数组长度为lenA
{                                                    ///b数组长度为lenB
    int aStr = 0,bStr = 0,cStr = 0;   ///相当于指向a,b,c三个数组的指针。
    while(cStr<(lenA+lenB))
    {
        if(a[aStr]<b[bStr])   ///判断两个数组各自指针所指向的元素的大小,将较小的放进c中
        {
            c[cStr] = a[aStr];
            aStr ++;
            cStr ++;
        }
        else
        {
            c[cStr] = b[bStr];
            bStr ++;
            cStr ++;
        }

        if(aStr==lenA)   ///若其中一个数组的元素已经处理完,将另一个数组当中剩余
        {                ///的元素一次放入c中
            while(bStr<lenB)
            {
                c[cStr] = b[bStr];
                bStr ++;
                cStr ++;
            }
        }
        else if(bStr==lenB)
        {
            while(aStr<lenA)
            {
                c[cStr] = a[aStr];
                aStr ++;
                cStr ++;
            }
        }
    }
}

///归并算法的实现。
void mergeSort(int a[],int n)
{
    if(n>1)
    {
        ///首先是将a数组进行拆分
        int i = n/2;
        int j = n-n/2;
        int b[n/2];
        int c[n-n/2];

        for(int k=0;k<i;k++)
        {
            b[k] = a[k];
        }

        for(int k=0;k<j;k++)
        {
            c[k] = a[k+i];
        }

        mergeSort(b,i);
        mergeSort(c,j);
        Merge(b,c,a,i,j);
    }
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值