快速排序算法的应用

已知由n(n> 2)个正整数构成的集合A=\left \{ a_{_{k}}|0\leqslant k< n \right \},将其划分为两个不相交的子集A_{1}A_{2},元素的个数分别是n_{1}n_{2},A_{1}A_{2}中的元素之和分别为S_{1}S_{2}.设计一个尽可能高效的算法,满足|n_{1}-n_{2}|最小且|S_{1}-S_{2}|最大。

分析:在本题中要求|n_{1}-n_{2}|最小且|S_{1}-S_{2}|最大,因此我们首先可以想到的最简单直接的方法就是将集合A中的元素从小到大进行排序,然后将前n/2(向下取整)个元素划分在子集A_{1}中,剩下下的元素放入子集A_{2}中。这种方法显然是可以的。

下面我们来计算上述方法的时间复杂度,因为已知的排序算法中最低得时间复杂度为o(nlogn),因此该算法的最低时间复杂度是o(nlogn)。我们在仔细分析题目要求后该方法显然不是最优解,因为我们在将集合A中元素划分子集A_{1}A_{2}时,并不需要将集合A中元素,从小到大进行排序。我们只需要知道A[n/2]的元素值,然后将集合A中小于A[n/2]的元素划分到集合A_{1}中,将其余元素划分到A_{2}中即可。

我们可以发现和快速排序算法中的寻找枢轴值的方法非常相似。因为在快速排序算法中,每次排序都是将待排序元素中大于枢轴元的元素放在枢轴元的右边,小于枢轴元的元素放在枢轴元的左边(默认从小到大进行排序)。因此对于上述题目我们只需要比较枢轴元的位置kn/2大小关系。有三种情况:

1:当k==n/2时满足条件。

2:当k>n/2时对中[0....k-1]元素中重新寻找枢轴元素

3:当K<n/2时在A[k+1...n-1]元素中重新寻找枢轴元素

重复上述步骤,直到k==n/2为止

对于上述算法的时间复杂度为o(n)。

c语言代码实现

#include <stdio.h>
#include <stdlib.h>

#define maxsize 100

int setpartition(int A[],int n)
{
    int flog=1;//flog相当于一个标记,用于判断枢轴元的位置k与n/2-1是否相等
    int s1,s2;//用于记录集合A1和A2的元素和
    int temp;//作为一个临时变量用于记录当前的枢轴元素值
    int i;
    int low,low0;//low0用于记录所需要排序元素的下界
    low=low0=0;
    int high,high0;//high0用于记录所需排序元素的上界
    high=high0=n-1;
    while(flog)//当flog==0时循环结束
    {
       temp=A[low];
       while(low<high)
       {
       while(low<high&&A[high]>temp)
            high--;
       A[low]=A[high];
       while(low<high&&A[low]<temp)
            low++;
       A[high]=A[low];
       }
       A[low]=temp;
       if(low==n/2-1)
       {
          flog=0;//当low==n/2-1时表示已经找到了中间元素A[n/2-1],循环可以结束了
       }
       else if(low>n/2)
       {
        high0=--high;//更改上界
        low=low0;//在区间[low0,high-1]中继续查找
       }
       else
       {
           low0=++low;//更改下届
           high=high0;//在区间[low+1,high0]中继续查找
       }

    }
    s1=s2=0;
    for(i=0;i<n/2;i++)
    {
        s1=s1+A[i];
    }
    for(i=n/2;i<n;i++)
    {
        s2=s2+A[i];
    }
    return s2-s1;//返回|S2-S1|的值
}

int main()
{
    int A[maxsize];
    int n,i;
    printf("please input the number of the set\n");
    scanf("%d",&n);
    printf("please input the set");
    for(i=0;i<n;i++)
    {
        scanf("%d",&A[i]);
    }
    printf("%d",setpartition(A,n));
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值