Оглядываясь на ответ Итай, похоже, что он читает файл тысячу раз после выборки одной строки кода, тогда как истинная выборка коллектора должна проходить только по «ленте» один раз. Я разработал код для перебора кода один раз с реальной выборкой коллектора на основе этого и различных описаний в Интернете.
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;
public class reservoirSampling {
public static void main(String[] args) throws FileNotFoundException, IOException{
Sampler mySampler = new Sampler();
List myList = mySampler.sampler(10);
for(int index = 0;index sampler (int reservoirSize) throws FileNotFoundException, IOException
{
String currentLine=null;
//reservoirList is where our selected lines stored
List reservoirList= new ArrayList(reservoirSize);
// we will use this counter to count the current line number while iterating
int count=0;
Random ra = new Random();
int randomNumber = 0;
Scanner sc = new Scanner(new File("Open_source.html")).useDelimiter("\n");
while (sc.hasNext())
{
currentLine = sc.next();
count ++;
if (count<=reservoirSize)
{
reservoirList.add(currentLine);
}
else if ((randomNumber = (int) ra.nextInt(count))
Основная предпосылка заключается в том, что вы заполните резервуар, а затем вернитесь к нему и заполните случайные линии с вероятностью 1 / ReservoirSize. Надеюсь, это обеспечит более эффективный код. Пожалуйста, дайте мне знать, если это не сработает для вас, поскольку я буквально сбил его через полчаса.
Тип void
не имеет размера. Поэтому вы не можете использовать void *
для очистки массива. Вы не можете разыменовать этот тип по той же причине.
Вы должны привести к указателю с определенным типом:
void clean_buffer(void *ptr, size_t n)
{
unsigned char *my_ptr = ptr;
for (int i = 0; i < n; i++)
my_ptr[i]=0;
}
Вы должны позаботиться о том, чтобы размер, передаваемый вашей функции, не мог быть числом или массивами, потому что компилятор не может выполнять арифметику указателей с [114 ] указатели. А для размеров вы должны использовать size_t
Вместо этого вы должны передать размер массива в байтах:
int main(void)
{
float *pf;
int *pi;
pf = malloc(10*sizeof(float));
pi = malloc(10*sizeof(int));
clean_buffer( pf, 10*sizeof(float));
clean_buffer( pi, 10*sizeof(int));
return 0;
}
Или вам нужно передать любую другую информацию, которая может быть использована для определить тип и / или размер данных.
Также: приведение к возвращаемому значению malloc
не требуется в C. Приведение параметров clean_buffer
к типу, который уже имеет переменную, бесполезно. Тип указателя в любом случае преобразуется в void *
, поскольку это то, что ожидает функция.
Примечание: в других ответах и комментариях упоминается, что вы можете просто передать указатель на memset
или использовать calloc
и т. Д. Это может быть верно для этого очень специфического случая, но если вы хотите сделать что-то еще, кроме простого обнуления памяти применимы те же аспекты, что и к указателям void *
, как я показал здесь. И в этих случаях memset
или calloc
не помогают.
void - это не значение, которое нельзя использовать *((void*) x) = v;
, и использование приведения для использования указателя на другой тип опасно , поскольку размер может не совпадать
Но в вашем случае вы установили 0, поэтому вы можете использовать memset или заменить malloc my calloc и бесполезно иметь clean_buffer
:
int main(void)
{
float *pf;
int *pi;
pf = calloc(10, sizeof(float));
pi = calloc(10, sizeof(int));
return 0;
}
void clean_buffer (void * ptr, int n)
blockquote>Эта функция требует void * в качестве параметра.
clean_buffer ((float *) pf, 10);
blockquote>Здесь вы приводите к указателю с плавающей точкой. Так что это другой тип по требованию
Также void не имеет размера, поэтому вы не можете использовать [] на ptr
.
Вы приводите ptr
к соответствующему типу, чтобы он мог разыменовать, чтобы очистить то, на что он указывает; что-то, что вы знаете, указывает на тип, который вы хотите очистить i
элементов.
У меня проблема с использованием void *. Как мне сделать, чтобы использовать эту функцию clean_buffer для массивов int и float (?)
blockquote>Другие упоминали полезные вещи, такие как необходимость
sizeof
найти размер, приведение не требуется и альтернативы используйтеcalloc()
для нулевого инициализированного выделения памяти.
Добавить:
sizeof * object_pointer
Используйте
sizeof *object_pointer
, чтобы найти размер. Он менее подвержен ошибкам, его легче просматривать и поддерживать, чем кодировать в типе.// clean_buffer( (float *)pf, 10); // clean_buffer( (int *)pi, 10); // cast not needed clean_buffer(pf, sizeof *pf * 10); // No need to mention type! clean_buffer(pi, sizeof *pi * 10);
volatile
Очистка памяти после ее окончательного использования склонна к оптимизации, а затем веская причина для не использовать
memset()
, когда память безопасность вызывает беспокойство. Вместо этого используйтеvolatile
, чтобы не допустить оптимизации самогоclean_buffer()
.void clean_buffer(void *ptr, size_t n) { volatile unsigned char *vuc = ptr; for(size_t i = 0; i < n; i++) vuc[i]=0; } }
malloc
сам по себе возвращает пустой указатель, так как он на самом деле не знает, для какого типа вы выделяете память. Итак, вам нужно использовать тот же размер, который вы передаете malloc
для очистки буфера.
Вы можете использовать memset
и передать размер всего буфера, чтобы очистить его, не беспокоясь о его типе.
void clean_buffer( void *ptr, size_t n)
{
memset(ptr, 0, n)
}
int main(void)
{
float *pf;
int *pi;
pf = (float *) malloc(10*sizeof(float));
pi = (int *)malloc(10*sizeof(int));
clean_buffer(pf, 10*sizeof(float));
clean_buffer(pi, 10*sizeof(int));
return 0;
}
Кроме того, как предлагали другие, вы можете использовать calloc
, если вам это подходит.