zoukankan      html  css  js  c++  java
  • 【快速选择算法与nth_element函数】【续UVA11300 】

    在白书中提到了一种O(n)级别的寻找中位数算法 就是我们今天要介绍的主角


    快速选择算法

    类似快排 选择一个比较元素 进行递归处理寻找第k大元素

    假设最后比较元素到了i


    以下描述是我写快排的常用字符 所以外人应该看不懂。。。。

    如果(i-s+1)<k  去(i+1,t)的区间  递归寻找第(k-(i-s+1)) 大的数

    如果(i-s+1)=k 返还i的值即可

    如果 (i-s+1)>k 去 (s,i-1)的区间 递归找第k大的数  


    类似快排的思想 很容易理解

    代码如下:

    int swap(long long &a,long long &b) {long long temp=a;a=b;b=temp;return 0;}
    int quickchoice(long long *A,int s,int t,int k)
    {
    	int i=s,j=t;
    	long long x=A[s];
    	while(i<j)
    	{
    		while(i<j&&A[j]>=x) j--;
    		if(i<j) swap(A[i],A[j]),i++;
    		while(i<j&&A[i]<x)  i++;
    		if(i<j) swap(A[j],A[i]),j--;
    	}
    	A[i]=x;
    	if((i-s+1)==k) return 0;
    	else if((i-s+1)<k&&i+1<=t) quickchoice(A,i+1,t,k-(i-s+1));
    	else if((i-s+1)>k&&s<=i-1) quickchoice(A,s,i-1,k);  
    	return 0;
    }


    UVA11300快速选择算法实现如下:

    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    using namespace std;
    long long gold[1000100],M;
    int cmp(const void *i,const void *j)
    {
    	if(*(long long *)i>*(long long *)j) return 1;
    	else if(* (long long *)i==*(long long *)j) return 0;
    	else return -1;
    }
    int main()
    {
    	int n,k;
    	long long sum;
    	while(scanf("%d",&n)!=EOF)
    	{
    		sum=0;
    		for(int i=1;i<=n;i++)
    		{
    			scanf("%lld",&gold[i]);
    			sum+=gold[i];
    		}
    		M=sum/n;
     		for(int i=1;i<=n-1;i++)
    		gold[i]=gold[i-1]+M-gold[i];
    		gold[n]=0;
    		qsort(gold+1,n,sizeof(gold[1]),cmp);
    		k=(n+1)/2;
    		sum=0;
    		for(int i=1;i<=n;i++)
    		sum=sum+abs(gold[i]-gold[k]);
    		printf("%lld
    ",sum);
    	}
    	return 0;
    }

    上面这个方法不知道为何 速度和快排没什么区别。。


    但是下面这个就快了一倍  

    nth_element函数 非常奇怪

    好吧 觉得奇怪 是被网上各种奇葩的资料误导了

    自己亲手操作后还是懂了

    nth_element(begin,kth,end)

    在[begin,end)这段区间内找第k大的数 其实这样描述是不精确的

    这样描述似乎更合适

    比如 nth_element(s+1,s+k,s+n+1)

    在[1,n+1)这段区间内 s[k] 左边的全部小于等于他 右边的全部大于等于他

    如果 区间从1开始 似乎确实可以描述成 第k个 

    如果不从1开始就注意点


    AC代码如下:

    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<algorithm>
    using namespace std;
    long long gold[1000100],M;
    int n;
    int main()
    {
    	int k;
    	long long sum;
    	while(scanf("%d",&n)!=EOF)
    	{
    		sum=0;
    		for(int i=1;i<=n;i++)
    		{
    			scanf("%lld",&gold[i]);
    			sum+=gold[i];
    		}
    		M=sum/n;
     		for(int i=1;i<=n-1;i++)
    		gold[i]=gold[i-1]+M-gold[i];
    		gold[n]=0;
    		k=(n+1)/2;	
    		nth_element(gold+1,gold+k,gold+1+n);
    		for(int i=1;i<=n;i++)
    		printf("gold:%d
    ",gold[i]);
    		sum=0;
    		for(int i=1;i<=n;i++)
    		sum=sum+abs(gold[i]-gold[k]);
    		printf("%lld
    ",sum);
    	}
    	return 0;
    }
    



  • 相关阅读:
    注册tomcat为服务
    BootStrap
    Passive DNS
    一个插件平台
    HDU 4394 BFS
    设计模式--组合模式--商品排序案例
    Windows平台编译openssl-0.9.8k库(32位、64位)
    JavaScript之this释疑
    OpenLayers3基础教程——OL3 介绍control
    我的Android进阶之旅------&gt; Android为TextView组件中显示的文本加入背景色
  • 原文地址:https://www.cnblogs.com/zy691357966/p/5480467.html
Copyright © 2011-2022 走看看