LINUX.ORG.RU

Алгоритм прост: 1. Узнать кол-во строк в файле. 2. Найти случайное число N в диапазоне 1..<кол-во строк> (смотри man 3 random) 3. Вернуть N-ую строку из файла.

Удачи!

anonymous
()

Выбирай всегда слово номер 4. Может потом пойдешь мэйнтэйнить openssl в дебиане.

anonymous
()
Ответ на: комментарий от anonymous

> Выбирай всегда слово номер 4. Может потом пойдешь мэйнтэйнить openssl в дебиане.

смеялся. хотя конечно шутка злая.

www_linux_org_ru ★★★★★
()

Если не обращать на шутников :)))

Алгоритм прост:

0) Читаем все что связано с потоковым чтением из файла через функции fopen(),fgets и прочими.

1) Рассчитываешь кол-во n-строк. Man fgets().

2) По кол-ву строк выделяешь динамически память на n-указателей по количеству найденных слов. Читаем в учебнике по С все, что касается двухмерных массивов и выделения памяти malloc(), calloc(). Объявляем двухмерный массив

char** words;

3) Далее вычитываешь тем же самым fgets() с одновременным выделением памяти под слово. words[n-1] = fgets();

4) Получаешь с помощью random() случайное слово: words[ random() % n ], где n-кол-во слов в файле.

5) Не забываешь освободить всю выделенную память.

rjaan ★★
()

На самом деле, достаточно иметь буфер на одну строку и счётчик прочитанных строк. На n-м шаге содержимое буфера заменяется на только что прочитанную строку с вероятностью 1/n.

Почему это будет работать? По индукции!

lodin ★★★★
()

если равномерное раперделение ненужно, то прыгаешь на случайную позицию в файле и идешь до символа переноса строки, потом читаешь все в буфер до следующего символа - вот и все.

wfrr ★★☆
()

> Помогите пожалуйста с выбором алгоритма,подтолкните в нужное направление, совсем запуталась. Программа на С.

мапишь файл в память. выбираешь rand() % mapped_file_size. далее по указателю ищешь следующий перевод строки и выводишь строку от этого указателя до следующего перевода строки. Всё просто.

stpg
()
Ответ на: комментарий от lodin

> На самом деле, достаточно иметь буфер на одну строку и счётчик прочитанных строк. На n-м шаге содержимое буфера заменяется на только что прочитанную строку с вероятностью 1/n.

Ага. Чудесный алгоритм! Вот кратчайший путь к этому знанию:

perldoc -q "random line"

alexsaa
()
Ответ на: комментарий от stpg

+1 самое разумное, но можно еще упростить: имея размер файла выбрать значение от 0 до размера файла, потом прыгнуть туда в файле через fseek и прочитать со следующего перевода строки.

Но для честности советую почитать книжки про рандомизацию в C, т.к. прыжок на 123 и 124 байты с последующим чтением после перевода строки может дать одно слово - "жопа".

:-)

anonymous
()
Ответ на: комментарий от stpg

это если текст восьмибитный
а если же утф-8 то тогда жопа

anonymous
()
Ответ на: комментарий от anonymous

> книжки про рандомизацию в C, т.к. прыжок на 123 и 124 байты с последующим чтением после перевода строки может дать одно слово - "жопа".

ну и при чем тут С?

элементарный теорвер же

anonymous
()
Ответ на: комментарий от stpg

> мапишь файл в память. выбираешь rand() % mapped_file_size. далее по указателю ищешь следующий перевод строки и выводишь строку от этого указателя до следующего перевода строки. Всё просто.

только вероятность выбора строки оказывается неравномерной (пропорциональна длине предыдущей строки); врочем, этот алгоритм несложно скорректоровать, так чтобы получилось равномерное распределение.

anonymous
()
Ответ на: комментарий от anonymous

А если вот так считываю весь файл, подсчитываю количество переносов строки, потом случайно выбираю и после него считываю строку до следующего переноса?!

aunt
() автор топика
Ответ на: комментарий от aunt

> подсчитываю количество переносов строки, потом случайно выбираю

случайно выбираю что? это надо все позиции переносов запомнить гдето же, а это уже не "подсчитываю"

и если собираешься считывать весь файл то выше уже предложили решение с 1/n.

anonymous
()
Ответ на: комментарий от anonymous

> случайно выбираю что? это надо все позиции переносов запомнить гдето же, а это уже не "подсчитываю" и если собираешься считывать весь файл то выше уже предложили решение с 1/n.

Подсчитываю количество '\n' чтобы знать сколько строк, например оказалось 500. Сохраняю значение в какой-то переменной. Потом случайно выбираю значение от 1 до 500, например 100, перехожу на 100 значение '\n' выбираю следующую строку за ним. Вот и всё.

А решение 1/n что-то непонятно, можно подробней?!

aunt
() автор топика
Ответ на: комментарий от anonymous

>впрочем, этот алгоритм несложно скорректировать, так чтобы получилось равномерное распределение.

Мне что-то кажется, что скорректировать его можно только предварительным индексированием файла (какая-нибудь fortune, скорее всего, так и делает).

lodin ★★★★
()
Ответ на: комментарий от lodin

не обязательно

суть такова:
1) выбираем случайную позицию в файле, например X.
2) X оказывается внутри какого-то слова (или строки), длины N.
3) кидаем монетку и с вероятностью 1/N возвращаем найденное слово
если же не повезло, начинаем заново с пункта 1

Нетрудно доказать, что вероятность выбора любого слова будет одинакова

Причем если длина файла стремится к бесконечности, а слова в среднем короткие,
получаем очевидный профит (в сравнении с решением при котором требуется
прочитать весь файл).

элементано же

anonymous
()
Ответ на: комментарий от anonymous

алсо: на шаге 2 потребуется прочитать какой-то кусок файла, но возможно не очень большой; на шаге 3 возможно надо брать 1/(N+1) или 1/(N+2), в зависимости от того как сколько байт в индикаторе конца строки

anonymous
()
Ответ на: комментарий от aunt

> А решение 1/n что-то непонятно, можно подробней?!

Перед началом чтения файла создаёшь переменную "текущий результат".

Затем открываешь файл и начинаешь читать его строка за строкой. Первую считанную строку безусловно копируешь в эту переменную.

Если на этом файл закончится, то в "текущем результате" будет "случайно выбранная" единственная строка файла.

Если в файле есть вторая строка, то заменяешь "текущий результат" второй строкой с вероятностью 1/2.

Если на этом файл закончится, то в "текущем результате" окажется с вероятностью 1/2 первая строка и с вероятностью 1/2 - вторая строка.

Если файл не заканчивается, и далее считана третья строка, то кладёшь её в "текущий результат" с вероятностью 1/3. После этого в "текущем результате" оказывается третья строка с вероятностью 1/3, а первая и вторая - каждая с вероятностью (1-1/3)*1/2 = 1/3. То есть снова равновероятно.

И т.д.

Если хочешь код, надо назвать желаемый язык.

Некоторый недостаток этого метода - приходится генерировать довольно много случайных чисел. Главное преимущество - файл читается только ровно раз.

alexsaa
()
Ответ на: комментарий от anonymous

> http://en.wikipedia.org/wiki/Rejection_sampling

И ведь действительно, классика... Спасибо.

Но всё равно это уже алгоритмы другого класса, нежели остальные предложенные. Ведь он не гарантирует завершение работы ни за какое конечное время. Поэтому писать "несложно скорректировать" - имхо некоторое лукавство.

alexsaa
()
Ответ на: комментарий от alexsaa

Программа получилась. Вот вывод time

real 0m0.012s
user 0m0.008s
sys 0m0.004s

Это при 9461 слове, это нормально?!

aunt
() автор топика
Ответ на: комментарий от aunt

> Это при 9461 слове, это нормально?!

Почему бы и нет? Вроде, задачи сделать это сверхбыстро не ставилось. Примерно 1 млн слов в секунду. Если считать, что слово занимает 7 байт, получается 7 Мб/сек. По-моему, неплохо. Если надо быстрее, надо посмотреть, на что уходит время.

alexsaa
()
Ответ на: комментарий от alexsaa


> Почему бы и нет? Вроде, задачи сделать это сверхбыстро не ставилос


+1

если конечно это не программа для работы с банковскими картами
где требуется минимум операций.

anonymous
()
Ответ на: комментарий от stpg

>далее по указателю ищешь следующий перевод строки и выводишь строку от этого указателя до следующего перевода строки.

ага. а если прыгнет на последнюю строку?

эх, программисты...

xydo ★★
()
Ответ на: комментарий от xydo

> ага. а если прыгнет на последнюю строку?

файл сделай циклический же

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.