| 
 Быстрее, еще быстрее
 
 Автор: Еремеев АлексейВ продолжение разговора на тему "Быстрее, еще быстрее" и, в частности, к 
таблицам перекодировок эта небольшая статья-обзор. 
 Насчет таблиц перекодировок и трансляции  (преобразованию данных) вообще.
Любимый прием программистов (и я через это проходил) создавать цикл 
трансляции строк вида (для простоты возьмем случай, когда выполняется 
преобразование байт-в-байт, вроде перекодировок ANSI-DOS):
 
function TranslateString(Source: string): string;
var
  i: integer;
begin
  Result := '';
  for i := 1 to Length(Source) do
    Result := Result + TranslateChar(Source[i]);
end;Это ужасно медленно! Загвоздка тут в конструкции Result := Result + 
...Каждый раз при добавлении одного байта к строке происходит переаллокация 
памяти и копирование уже существующего начала в новую область памяти, потом 
удаление старой области.
 Я бы сделал процедуру с var параметром и делал бы в 
цикле так:
 
procedure TranslateString(var Source: string);
var
  i: integer;
begin
  for i := 1 to Length(Source) do
    Source[i] := TranslateChar(Source[i]);
end;Или, если очень нужна функция, то так: 
function TranslateString(const Source: string): string;
var
  i: integer;
begin
  SetLength(Result, Length(Source));
  for i := 1 to Length(Source) do
    Result[i] := TranslateChar(Source[i]);
end;А уж пример трансляции с обратным поиском (см. Вариант1 Таблиц 
перекодировки на http://www.delphikingdom.com/treasury/decod.htm) 
- это вообще ночной кошмар микропроцессора!Если нет прямой таблицы 
преобразования, ее нужно сначала создать из обратной (одного раза за сеанс 
достаточно :-), а потом ее использовать. 
  
  
    Что лучше? (Вопросы от 
  Сашы)
>> И вот для меня не очевидно чем первое 
лучше второго.
 
if A > B then
  C := A
else
  C := B;
и
C := A;
if A < B then
  C := B;Очевидно. Во втором случае присваивание C:=A будет выполнятся в любом 
случае, даже если A<B. Налицо лишняя команда. Хотя в разных случаях может 
быть по разному. Что лучше, лишний MOV или лишний JMP ? А если строки 
присваиваются?
 >> А конструкции if then else if then .... И 
сase ofТут все зависит от конкретной ситуации. Если речь идет о 
перечислимых типах, то скорее всего лучше подойдет case. С точки зрения 
исходного кода эти две конструкции равнозначны. А вот если нужно сравнивать 
строки, то case тут не поможет. (поправьте, если я не прав) >> A for i:=0 to 10 do И i:=0; while I<=10 do 
i:=i+1;И тут все зависит от ситуации. В ощем виде можно сказать 
так, что цикл while необходим в следующих случаях: 
  когда шаг цикла может меняться внутри цикла 
  когда кол-во итераций может менятся внутри цикла 
  когда используется значение переменной цикла после выхода из цикла 
 >> И классический пример рекурсии 
function Factorial(N: Longword): Longword;
begin
  Result := 1;
  if N < 1 then
    exit;
  Result := N * Fuctorial(N - 1);
end;
И
function Factorial(N: Longword): Longword;
var
  I: Longword;
begin
  Result := 1;
  for I := 1 to N do
    Result := Result * I;
end;Рекурсия - вообще дело тонкое :-) Снова надо говорить о частностях. 
Первое, о чем надо подумать, это максимально возможная глубина спуска. Если есть 
вероятность переполнения стека - сразу отбрасывайте прямой рекурсивный 
способ.Если уж никак не обойтись без глубокой рекурсии, можно реализовать 
что-то типа суррогатного стека ручным способом. Это муторно однако. Ну и если 
есть простой итеративный способ - на мой взгляд лучше воспользоватся им. (Хотя 
согласен - изящная рекурсия - оч-ч-чень красиво!) 
  
  
    Итог
В общем случае, если не касаться специальных математических методов 
оптимизации в предметной области то исходить нужно из исходной задачи и здравого 
смысла. Хотя здравый смысл нужен всегда :-)
 |