2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему
 
 Помогите решить задачу по паскалю на тему файлы :!:
Сообщение06.12.2009, 05:23 


06/12/09
7
Создать файл F, заполненный целыми числами из диапазона [1,20].
Удалить из файла F повторяющиеся включения одного и того же числа.
ПРИМЕР: 10 13 2 5 6 7 6 9 10 2
13 2 5 6 7 9
Вот моя неработающая прога!!
код: [ скачать ] [ спрятать ]
Используется синтаксис Pascal
program lab;
var f:file of integer; i,j,a,b,c,d,e,r,h,y:integer;
begin
Assign (f,'lab3.dat');
rewrite (f);
writeln ('vvedite kol-vo elementov v faile');
readln (a);
randomize;
for i:=0 to a-1 do begin
h:=random(20);
write (f,h);
end;
seek (f,0);
while not eof(f) do begin
read (f,h);
write (h,' ');
end;
for i:=0 to a-2 do begin
seek (f,i);
read (f,b);
for r:=i+1 to a-1 do begin
seek (f,r);
read (f,b);
if r=b then begin
seek(f,r+1);
read(f,d);
seek(f,filepos(f)-1);
write (f,d);
for j:=filepos(f) to a-1 do begin
seek (f,filepos(f)+1);
read (f,e);
seek (f,filepos(f)-2);
write (f,e);
end;
end;
 

Происходит вылет за пределы файла!!!
Не знаю что и делать,
помогите пожалуйста!!!
Заранее премного благодарен.

 Профиль  
                  
 
 Re: Помогите решить задачу по паскалю на тему файлы :!:
Сообщение06.12.2009, 07:45 


06/12/09
7
Ну помогииитеее!!!!!

 Профиль  
                  
 
 Re: Помогите решить задачу по паскалю на тему файлы :!:
Сообщение06.12.2009, 11:55 
Заслуженный участник


11/05/08
32166
Во-первых, обрамите программу тегом code и расставьте отступы -- читать невозможно. Во-вторых, после записи файла его следовало бы сперва закрыть, а потом переоткрыть как Reset -- хотя бы для приличия (и вообще записываемые или перезаписываемые файлы следует закрывать, иначе может быть потерян последний буфер). В-третьих, если Вы выкидываете что-то из файла, то в конце необходим Truncate -- для фиксации нового размера файла, иначе у него в хвосте останется мусор.

Теперь по поводу собственно алгоритма. Во-первых, у Вас числа получаются не от 1 до 20, а от 0 до 19. Во-вторых, проверка "if r=b" явно ошибочна (первое -- это адрес в файле, второе же -- значение поля по какому-то адресу). В-третьих, если у Вас этот адресный счётчик меняется вплоть до конца файла ("for r:=i+1 to a-1"), а потом Вы пишете "seek(f,r+1);" -- чего ж и удивляться возможному вылету.
В-четвёртых, вообще алгоритм странен. Заведите два счётчика: первый -- на то поле, которое подлежит переписыванию (при необходимости), а второй -- на поле, проверяемое на несовпадение с предыдущими. Если очередное поле по второму адресу не совпадает ни с одним из предыдущих (вплоть до первого адреса минус один), то его значение перезаписывается по первому адресу, после чего первый счётчик увеличивается на единичку.

 Профиль  
                  
 
 Re: Помогите решить задачу по паскалю на тему файлы :!:
Сообщение06.12.2009, 12:37 


13/09/09
72
Я вот щас сел разбиратся и не понял идею Вашей программы....Давайте разбиратся:
Код:
for i:=0 to a-2 do begin
  seek (f,i);
  read (f,b);
for r:=i+1 to a-1 do begin
  seek (f,r);
  read (f,b);

Вы записываете в переменную b значение текущей ячейки. Потом в следующем цикле Вы перезаписываете эту переменную на значение следующей ячейки....Зачем?
Код:
if r=b then begin

Вы сравниваете номер ячейки с ее номером в файле.
Код:
seek(f,r+1);
read(f,d);
seek(f,filepos(f)-1);

write (f,d);
for j:=filepos(f) to a-1 do begin
seek (f,filepos(f)+1);
read (f,e);
seek (f,filepos(f)-2);
write (f,e);
end;

Вот здесь Вы обращаетесь к элементу r+1, из за этого и происходит выход за границы файла.
В этой части у вас вероятно происходит смещение элементов на место удаленного, но идею я не понял.
Не делайте столько вложенный циклов очень сложно в этом потом будет разобратся. Лучше вообще сделать отдельную функцию куда Вы будете передавать номера повторных элементов.

 Профиль  
                  
 
 Re: Помогите решить задачу по паскалю на тему файлы :!:
Сообщение07.12.2009, 07:03 
Заслуженный участник


26/07/09
1559
Алматы
2sir.andrey
Цитата:
Удалить из файла F повторяющиеся включения одного и того же числа.
ПРИМЕР: 10 13 2 5 6 7 6 9 10 2
13 2 5 6 7 9

Ничего не понятно. Нужно удалять повторяющиеся числа вообще или все-таки оставлять одно из их вхождений? В первом случае ваш пример бы выглядел как 10 13 2 5 6 7 6 9 10 2 -> 13 5 7 9, во втором -- как 10 13 2 5 6 7 6 9 10 2 -> 10 13 2 5 6 7 9. А у вас ни то, ни другое... Похоже на анекдот, в котором на вопрос "что пишешь?" программист отвечает "запустим -- узнаем". :)

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

Если же вам надо удалить все вхождения повторяющихся чисел, то можно создать два временных файла, первый будет копией исходного, а второй -- пустым (в начале). Опять же, читаете исходный файл и ищите каждое число из него в первом временном файле, если вхождений ровно одно -- копируете текущее число во второй временный файл. В конце удаляете оригинальный и первый временный файл (копию исходного), второй же выдаете за результат работы.

Преимущество такого подхода заключается в простоте кода и, в частности, в отсутствии необходимости использования функции seek(...). А вот когда все заработает, тогда уже и об оптимизации можно будет подумать... :)

 Профиль  
                  
 
 Re: Помогите решить задачу по паскалю на тему файлы :!:
Сообщение07.12.2009, 09:14 
Заслуженный участник


11/05/08
32166
Circiter в сообщении #268617 писал(а):
Опять же, читаете исходный файл и ищите каждое число из него в первом временном файле, если вхождений ровно одно -- копируете текущее число во второй временный файл.

Неэффективно. Проще (пользуясь тем, что числа лишь из диапазона 1..20) завести массив из 20 счётчиков вхождений для каждого возможного числа. При первом проходе подсчитываются количества вхождений. При втором -- перезаписываем только числа, имеющие одно вхождение.

 Профиль  
                  
 
 Re: Помогите решить задачу по паскалю на тему файлы :!:
Сообщение09.12.2009, 03:08 
Заслуженный участник


26/07/09
1559
Алматы
2ewert
Цитата:
При первом проходе подсчитываются количества вхождений. При втором -- перезаписываем только числа, имеющие одно вхождение.

Что ж, гениально. Правильно ли я вас понял, вы предлагаете сначала сделать примерно так::
Используется синтаксис Pascal
    while not Eof(SourceFile) do
    begin
        Read(SourceFile, CurrentItem);
        Inc(Frequencies[CurrentItem]);
    end;
 

А потом так:
Используется синтаксис Pascal
    while not Eof(SourceFile) do
    begin
        Read(SourceFile, CurrentItem);
        if Frequencies[CurrentItem]=1 then
            Write(DestinationFile, CurrentItem);
    end;
 

Ok, это решает задачу удаления повторяющихся чисел. Если нужно сохранить одно из вхождений каждого числа, то реализацию второго прохода нужно будет немного модифицировать, а именно заменить
Используется синтаксис Pascal
    if Frequencies[CurrentItem]=1 then
        Write(DestinationFile, CurrentItem);
 

на фрагмент
Используется синтаксис Pascal
    if Frequencies[CurrentItem]>0 then
    begin
        Write(DestinationFile, CurrentItem);
        Frequencies[CurrentItem]=0;
    end;
 

Вроде так...

 Профиль  
                  
 
 Re: Помогите решить задачу по паскалю на тему файлы :!:
Сообщение09.12.2009, 08:21 
Заслуженный участник


11/05/08
32166
В принципе, ровно так. Разве что строчку из первого фрагмента я бы на всякий случай дополнил:

Код:
if Frequencies[CurrentItem]<2
    then Inc(Frequencies[CurrentItem]);

(мало ли, а вдруг входной файл -- чёрт-те какой длины?...)

 Профиль  
                  
 
 Re: Помогите решить задачу по паскалю на тему файлы :!:
Сообщение16.12.2009, 11:25 
Заслуженный участник


26/07/09
1559
Алматы
Для второго варианта (с сохранением одного из вхождений) вроде-бы можно написать однопроходный алгоритм с использованием паскалевских множеств:

Используется синтаксис Pascal
var Items: set of 1..20;

    ...

while not Eof(SourceFile) do
begin
    Read(SourceFile, CurrentItem);
    if not (CurrentItem in Items) then
    begin
        Items:=Items+[CurrentItem];
        Write(DestinationFile, CurrentItem);
    end;
end;
 

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 9 ] 

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group