Консультация № 172329
19.09.2009, 10:28
0.00 руб.
19.09.2009, 11:31
0 11 0
Здраствуйте уважаемые эксперты, возникла проблема: по заданию создал програмку в ТП, вроде всё должно работать, проблем с кодом как таковых нет, но компилятор упрямо отказывается корректно обработать код.
Программа заключается в следущем: Дан текст, 200 слов, программа читает текст, и создает хэш таблицу, после чего выводит количество одинаковых элементов и количество коллизий...
Программа:
Код:
Program lab5;
uses crt;
const
n=1000;
type cell = record
slov:string[50];
key: integer;
end;
var
kolcol,kolsl,sel,quit,i,j,x,k:integer;{переменные}
s,s1:string;
ch:char;
f1:text;
hashtbl: array[0..n] of cell;
bool:boolean;

{Функция получения ХЭШ кода слова}
Function hash(s1:string): Integer;
var res,ti,code:integer;
st:string;
begin
res:=0;
for i:=1 to length(s1) do
res:=(255*res+abs(ord(s1[i])))mod kolsl;
hash:=res;
end;

{Функция сравнения слов}
Function StrCm(s3,s4:string): Integer;
var bool2:boolean; kp:integer;
begin
bool2:=false;
kp:=1;
StrCm:=0;
If length(s3)=length(s4) then
while (bool2<>true) and (length(s3)<>kp) do
begin
if s3[kp]<>s4[kp] then
begin
bool2:=true;
StrCm:=1;
end
else
begin
kp:=kp+1;
end;
end
else
StrCm:=1;


end;





{Метод линейных проб}
procedure linpro(s1:string);
var st,s2:array [0..50] of char;
hs,num,res:integer;
begin
{Получаем ХЭШ код слова}
hs:=hash(s1);
num:=hs;
{Ищем в массиве место для данного кода}
bool:=true;
while (bool=true) do
begin
{Если в ячейке есть значение, то коллизия}
if hashtbl[num].key<>0 then
begin
res:=StrCm(hashtbl[num].slov,s1);
If res<>0 then
begin
kolcol:=kolcol+1;
num:=num+1;
if (num>kolsl) and (num<n) then kolsl:=num;
if (num>n) then num:=num mod n;
end
else
begin
bool:=false;
end;
end
else
begin
Hashtbl[num].slov:=s1;
hashtbl[num].key:=num;
bool:=false;
end;

end;
end;


{Метод квадратичных проб}
procedure kvpro(s1:string);
var
hs,num,zn,res:integer;
bool:boolean;
begin
Hs:=hash(s1);
num:=hs;
zn:=1;
i:=1;
{Поиск в массиве места для слова}
bool:=true;
while bool=true do
begin
{Если в ячейке есть значение, то коллизия}
if hashtbl[num].key<>0 then
begin
res:=StrCm(hashtbl[num].slov,s1);
If res<>0 then
begin
kolcol:=kolcol+1;
{Находим новую позицию как квадрат, меняем знак}
num:=(num+i*zn)+(num+i*zn);
zn:=zn*-1;
if zn=1 then i:=i+1;
if (num>kolsl) and (num<n) then kolsl:=num;
{Проверяем, не вышли ли за пределы массива}
if (num>n) then num:=num mod n;
if num<0 then num:=1;
end
else
bool:=false;
end
else
begin
Hashtbl[num].slov:=s;
hashtbl[num].key:=num;
bool:=false;
end;

end;
end;


{Вывод таблицы}
procedure writecell(h: array of cell);
begin
writeln('| KEY | Slovo | KEY | Slovo |');
for i:=1 to n do
begin
if h[i].key<>0 then
if i mod 40 <> 0 then
if i mod 2 = 0 then
writeln(h[i].key:16,h[i].slov:21)
else
write(h[i].key:16,h[i].slov:21)
else
readln;


end;
end;



begin {начало программы}
clrscr; {очистка экрана}
assign(f1,'Text.txt');
randomize;
while quit<>1 do
begin
clrscr;
writeln('-----------------------');
writeln('Laboratornaya rabota #5');
writeln('1. Prosmotr Teksta');
writeln('2. HASH');
writeln('3. Exit');
writeln('-----------------------');
writeln('----BY-HELL_Phoenix----');
readln(sel);
case sel of
1:
begin
clrscr;
reset(f1);
s:='';
while Not Eof(f1) Do
begin
read(f1,ch);
write(ch);
end;
readln;
end;
2:
begin
clrscr;
kolcol:=0;
kolsl:=200;
s:='';
{Обнуляем значения массива}
for i:=0 to n do
begin
hashtbl[i].key:=0;
hashtbl[i].slov:='';
end;
{Метод линейных проб}
assign(f1,'Text.txt');
reset(f1);
while not eof(f1) do
begin
read(f1,ch);
if ch<>' ' then
s:=s+ch
else
begin
linpro(s);
s:='';
end;

end;
j:=0;
for i:=1 to n do
if hashtbl[i].key<>0 then
j:=j+1;
clrscr;
Writeln('Lineynie probi: Ob"em tablici = ',j,' ','Collisiya = ',kolcol);
close(f1);
assign(f1,'Text.txt');
reset(f1);
kolsl:=200;
kolcol:=0;
s:='';
{Обнуляем значения массива}
for i:=0 to n do
begin
hashtbl[i].key:=0;
hashtbl[i].slov:='';
end;
{Метод квадратичных проб}
reset(f1);

while not eof(f1) do
begin
read(f1,ch);
if ch<>' ' then
s:=s+ch
else
begin
kvpro(s);
s:='';
end;
end;
j:=0;
for i:=1 to n do
if hashtbl[i].key<>0 then
j:=j+1;
writeln;
Writeln('Kvadratichnye probi: Ob"em tablici = ',j,' ','Collisiya = ',kolcol);
readln;
end;



3:
begin
break;
end;
end;
end;
end.

Текст в файле text.txt:
Код:
Not long after we moved to Paris, in the fall of 1995, my wife, Martha, and I saw, in the window of a shop on the rue Saint-Sulpice, a nineteenth-century engraving, done in the manner, though I'm now inclined to think not from the hand, of Daumier. It shows a train on its way from the Right Bank of Paris to the moon. The train has a steam locomotive and six cars, and it is chugging up a pretty steep track. The track is supported on two high, slender spires that seem to be anchored somewhere in the Fifth Arrondissement (you can see the Pantheon in silhouette nearby), and then the track just goes right up and touches the full moon up in the clouds. I suppose the two pillars are stronger than they look. The train is departing at twilight—presumably its an overnight trip—and among the crowd on the ground below, only a couple of top-hatted bourgeois watch the lunar ex press go on its way with any interest, much less wonder. Every body else in the crowd of thirteen or so people on the platform, mostly moms and dads and kids, are running around and making

Обсуждение

Неизвестный
19.09.2009, 10:29
общий
Текст должен быть в файле Text.txt
Неизвестный
19.09.2009, 10:31
общий
Проблема при обработке была такая: текст не выводится на экран после выполнения кэширования..
давно
Мастер-Эксперт
425
4118
19.09.2009, 11:33
общий
Hellphoenix:
"Хэширование" и "кэширование" - немного разные вещи. Определитесь, пожалуйста, о чём идёт речь.
Об авторе:
Я только в одном глубоко убеждён - не надо иметь убеждений! :)
давно
Мастер-Эксперт
425
4118
19.09.2009, 11:40
общий
Hellphoenix:
Вопрос из чистого любопытства:
А почему Вы в своей программе не пользуетесь русским языком?
Об авторе:
Я только в одном глубоко убеждён - не надо иметь убеждений! :)
давно
Мастер-Эксперт
425
4118
19.09.2009, 11:57
общий
У меня Ваша программа работает и даже выводит на экран какие-то данные. Проверять правильность выводимых данных мне не особо хочется, т.к. Ваш вопрос был совершенно о другом.
Однако попутно обнаружилась одна грубейшая ошибка:
После запуска программы я нажимаю цифру 1 (Просмотр текст) - текст выводится нормально.
Далее я нажимаю на цифру 2, чтобы заняться собственно хэшем, и получаю Run-time Error 5, который возникает из-за того, что пытаешься получить доступ к уже занятому файлу. Посмотрев текст программы я обнаружил любопытнейшую ситуацию - ажно 3 строки Assign(f1, 'Text.txt'); Это, интересно, зачем? Связывание файловой переменной с файлом вполне достаточно и одного, Вы ведь всё равно только его одного читаете. А ошибка возникает из-за того, что Вы проводите чтение файла не закрыв его после предыдущего чтения.
Код:
begin 	{начало программы}
clrscr; {очистка экрана}
assign(f1,'Text.txt');
...
case sel of
1:
begin
clrscr;
reset(f1);
...
2:
begin
...
assign(f1,'Text.txt');
reset(f1);
...

Об авторе:
Я только в одном глубоко убеждён - не надо иметь убеждений! :)
Неизвестный
19.09.2009, 12:06
общий
Не точто бы это было сделано неумышленно, но с моим интерпретатором что то не то творится, он временами делает очень необычные вещи: то компилировать отказывается, то говорит что текст не открыт для чтения/изменения и вообще ведет себя нестабильно....
Можно поинтересоваться, каким компилятором вы пользуетесь? У меня Turbo Pascal 7.
давно
Мастер-Эксперт
425
4118
19.09.2009, 12:24
общий
Hellphoenix:
Turbo Pascal 7 применялся только во времена доисторических динозавров. Ожидать от него нормальной работы в операционках типа W2k и выше, мягко говоря, легкомысленно, т.к. ТР7 разрабатывался с учётом особенностей MS-DOS, а многие эти особенности в Windows 2k уже не работают.
Я пользуюсь компилятором FreePascal для Windows. Он разработан с учётом специфики программирования в 32-ух и 64-ех разрядных ОС. Очень похож на Delphi, поэтому для тех кто раньше программировал в Delphi, а сейчас внезапно решил стать законопослушным гражданином и не использовать нелицензионные программы, переучиваться для работы в Freepascal нет абсолютно никакой необходимости.
Вот ссылка на сайт, где можно скачать FreePascal:
http://www.freepascal.org/
Об авторе:
Я только в одном глубоко убеждён - не надо иметь убеждений! :)
Неизвестный
19.09.2009, 14:12
общий
Hellphoenix:
Добрый день, Hellphoenix!
Для чего у Вас procedure writecell(h: array of cell); ?
Она нигде не используется.
Неизвестный
19.09.2009, 19:58
общий
процедура writecell использовалась во время отладки, остался эдакий атавизм :)
Неизвестный
19.09.2009, 20:42
общий
Hellphoenix:
У Вас проблему создает linpro(s). После того, как заремил строку - программа заработала
...............
while not eof(f1) do
begin
read(f1,ch);
if ch<>' ' then
s:=s+ch
else
begin
(* linpro(s);*)

s:='';
end;
..................
давно
Старший Модератор
31795
6196
21.09.2009, 17:05
общий
Hellphoenix:
Можно и я вилкой помахаю
1)
while quit<>1 do - значение переменной quit какое и где оно определяется? И Вы с этой переменной заходите в цикл с предусловием.
Радуйтесь, что ТР7, обнуляет все переменные после запуска программы, иначе долго искали бы свои ошибки(тут работает, а тут нет ). Если Вам нужно написать вечный цикл, то и пишите while true do. (Замечание больше по стилю, но использовать переменные, до определения их значения не корректно)

2)
1:
begin
. . .
reset(f1);
s:='';
. . .
end;

Файл открыли, закрывать кто будет и ещё, что там делает переменная s?
3)
kolsl:=200;
Откуда такая уверенность, что у Вас в хешируемой строке будет только 200 слов или зачем, тогда Вы изменяете значение kolsl в строке
if (num>kolsl) and (num<n) then kolsl:=num; - значит Вы не уверены именно в этом значении? Посчитать трудно в реальной строке? В контрольной строке есть и пробелы и знаки препинания. Слова без знака и со знаком в конце будет восприниматся как различные слова.
4)
Сам хеш написан с уже врожденной коллизией: одна причина - это знаки препинания, вторая это изменение переменной kolsl(хеши для одинаковых слов, при измененной переменной будут различны), третье- использование знаковых типов пременных.
Код:
var
a:word;
b:integer;
begin
a:=130;
b:=130;
write(a*255:10,b*255:10);
readln;
end.

Посмотрите ТР применяет различные методы зависящие от типа, в данном случае вывод числа.
Скачайте кинги Д.Кнут, "Искусство программирования". Хеширование описано в 3-ем томе, но Вам в любом случае будет полезно то множество алгоритмов расмотренное в данном 3-ёх томнике.

Это то, что касается критических замечаний.

Теперь о стиле:
5)
while (bool=true) do
Цитата: хелп ТР
While (зарезервированное слово)
Оператор цикла While содержит выражение, которое управляет повторением выполнения отдельного или составного оператора.
Синтаксис: While выражение Do оператор
Замечания: Оператор после Do будет выполняться до тех пор, пока булево выражением является истинным (True).

Вам вполне можно указать только саму логическую переменную, т.к. дополнительная проверка условия генерирует только лишний код.
6)
Использованиее глобальных переменных только увеличивает длину кода и иногда является источником некорректной работы программы. Лучше использовать локальные переменные, т.к. память под них отводится в стеке, т.е. выделяется только во время работы программы и не влияет на всю программу при работе.
7)
Вы работаете со строками, но не используете все возможности ТР, посмотрите код в следующем замечании, красивее и читабельнее.
8)
Функция StrCm возвращает только два значения (0 и 1), а это практически логическая переменная.
Посмотрите если её код переписать, на сколько он будет читаем.
Код:
Function StrCm(s3,s4:string): boolean;
var
bool2:boolean;
begin
bool2:=length(s3)=length(s4);
while (bool2) and (length(s3)>0) do
begin
bool2:=s3[1]=s4[1];
delete(s3,1,1);
delete(s4,1,1);
end;
StrCm:=bool2;
end;

Лишних переменных в коде тоже нет, как например в строчках:
Код:
hs:=hash(s1);
num:=hs;
. . .
res:=StrCm(hashtbl[num].slov,s1);
If res<>0 then
.
Эти переменные нигде больше не используются.

Можно было продолжать бесконечно по стилю, но думаю и этого достаточно.
Замечания по стилю Вы можете принять и использовать, если для Вас программирование будет важнее, иначе можете писать как Вам удобнее, если для Вас важнее результат.
Удачи!
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

Форма ответа