我的任务的一部分基于数组(其大小由用户给出),其包含从1到10 ^ 10的随机数。然后我们必须找到第k个较小的数组。这是我试过的:
#include <cstdlib>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <time.h>
using namespace std;
void swap(int *x,int *y)
{
int temp;
temp = *x;
*x = *y;
*y = temp;
}
int choose_pivot(int i,int j )
{
return((i+j) /2);
}
// Print array
void printarr(int arr[],int n)
{
int i;
for(i=0;i<n;i++)
printf("%d\t",arr[i]);
}
// Find algorithm
int find1(int arr[],int left,int right,int k)
{
int i,j,pivot;
if (left==right)
return arr[left];
else
{
i=left;
j=right+1;
pivot= arr[left];
do
{
do {
i=i+1;
} while (arr[i]>=pivot);
do {
j =j-1;
} while (arr[j]<=pivot);
if (i<j)
swap(arr[i],arr[j]);
} while (j<=i);
}
swap(arr[left],arr[j]);
if (k==j)
return arr[j];
else if (k<j)
find1(arr,left,j-1,k);
else
find1(arr,j+1,right,k-j);
}
int main(int argc, char *argv[])
{
srand(time(NULL));
int n,i,fi,k;
printf("Give array's size:\n");
scanf("%d",&n);
int pin[n];
for (i=0;i<n;i++)
pin[i]=((rand()*rand()) % 1000000000) +1;
printf("Give k: \n");
scanf("%d",&k);
printf("The array contains the following numbers:\n\n");
printarr(pin,n);
fi=find1(pin,0,n-1,k);//find the k-th smallest number in the array
printf("The k-th smallest number is: %d",fi);
system("PAUSE");
}
正如你所看到的,10 ^ 10是一个非常大的值,我用其他数字填充数组。这是对的吗?我还能做些什么吗? 我的第二个问题是查找算法。它不起作用。有人可以帮我这些吗?非常感谢你
答案 0 :(得分:3)
long long get_big_rand()
{
long long result;
do {
result = (rand() & 0x3ff);
result <<= 12;
result |= (rand() & 0xfff);
result <<= 12;
result |= (rand() & 0xfff);
} while (++result > 10000000000ULL);
return result;
}
答案 1 :(得分:2)
rand()*rand()
与单个rand()
有很大不同,它会降低随机性并更改其分布。有关更深入的解释,请参阅this question。
此外,整数通常为4个字节。如果它是未签名的,它可以包含一个大到2^31
(20亿美元)或2^32
(40亿甚至更多)的值。您可以查看INT_MAX
中定义的limits.h
宏可以包含的最大数量。 10^10
是10亿,它不适合整数,你必须使用更大的类型(long long
通常是64字节,因此比你需要的多。)
rand
也会返回最多RAND_MAX
的数字,因为它返回int
,所以它不会大于INT_MAX
。您应该使用其他方式生成与10^10
一样大的数字。
如果您不关心随机数和随机数分布,您可以将n
个随机数(由rand
获得)加总,以便n=10^10 / RAND_MAX
。
答案 2 :(得分:2)
如果仔细观察10 10 ,你会发现它是一个非常圆的限制。我对此的看法是生成每个数字,一次一个数字,忽略无关紧要的零。此时,您将有一个0到10之间的数字 10 -1(含)。你剩下的就是添加1。
至于random()*random()
,这是this other question的完全主题。
阿林
答案 3 :(得分:2)
问题#1,int只能容纳2 ^ 31大小的数字。您的引脚阵列需要稍大的替代方案。
此外,将两个随机数相加在一起确实没有太大作用 - 除非使数字更少随机。
接下来,您无法使用用户的输入动态地在堆栈上创建数组。这需要一个新的解决方案来为你分配一个数组。
答案 4 :(得分:1)
rand()* rand()不会为你做任何事情。它不会像你想象的那样扩展,它确实改变了分布。事实上
double norm_rand(){
double r=0;
for(unsigned i=0;i!=12;++i)
r+=rand()/static_cast<double>(RAND_MAX);
return (r/12)-6;
}
是模拟具有均值0和方差1的正态分布的常用方法;
获取大型随机数的最佳方法是使用随机数设备,如/ dev / urandom或RtlGenRandom。 即。
typedef unsigned long long big_type;
std::vector<double> rnums;
std::vector<big_type> buf(numtoread);
std::ifstream rnds("/dev/urandom");
rnds.read(reinterpret_cast<char*>(&buf[0],buf.size()*sizeof(big_type));
std::transform(buf.begin(),buf.end(),std::back_inserter(rnums),
[](big_type const& i){
return (i*100000000000.)/(std::numeric_limits<big_type>::max());
});
冒着为你做功课的风险,一种完全不同的方法是使用C ++附带的库。
#include <cassert>
#include <sstream>
#ifndef _MSC_VER //then assume Linux
#include <tr1/random>
#else
#include <random>
#endif
#include <boost/lexical_cast.hpp>
#include <algorithm>
#include <iterator>
#include <iostream>
int main(int argc, char** argv)
{
assert(argc==3);
unsigned const numentries=boost::lexical_cast<unsigned>(argv[1]);
unsigned const k=boost::lexical_cast<unsigned>(argv[2]);
std::cout<<" finding "<<k<<"th of "<< numentries<<" entries\n";
assert(k<=numentries);
std::vector<double> nums(numentries);
std::tr1::uniform_real<> rng(0.,10000000000.);
std::tr1::minstd_rand generator(42u);
std::tr1::variate_generator<std::tr1::minstd_rand, std::tr1::uniform_real<> >
uni(generator, rng);
std::generate_n(nums.begin(),nums.size(),uni);
std::cout<<" Generated:\t ";
std::copy(nums.begin(),nums.end(),std::ostream_iterator<double>(std::cout,"\t"));
std::sort(nums.begin(),nums.end());
std::cout<<"\n The "<<k<<"th smallest entry is "<<nums[k]<<"\n";
return 0;
}
(如果你在课堂上只是要求制作一系列兰特数字并将其交给他们,他们可能会让你失望) 我在实践中做的是结合这两种方法。这用于代替上面使用的线性conguentual rng(minstd_rand):
template<typename bigtype=unsigned>
struct randeng {
typedef bigtype result_type;
randeng(unsigned x) :
m_samplesrequired(x), m_samples(x), m_lastused() {
std::ifstream rand;
rand.open("/dev/urandom");
assert(rand);
rand.read(reinterpret_cast<char*> (&*(m_samples.begin())),
m_samplesrequired * sizeof(unsigned));
}
result_type operator()() const {
assert(m_lastused<m_samplesrequired);
return m_samples[m_lastused++];
}
result_type max() const {
return std::numeric_limits<result_type>::max();
}
result_type min() const {
return 0;
}
unsigned m_samplesrequired;
std::vector<result_type> m_samples;
mutable unsigned m_lastused;
};
这似乎总能给出更好的结果。
答案 5 :(得分:0)
find1
结束时你应该这样做:
if (k==j)
return arr[j];
else if (k<j)
return find1(arr,left,j-1,k);
else
return find1(arr,j+1,right,k-j);
}