Рассмотрим пример
Есть таблица, содержащая список студентов с указанием их роста и веса. Нужно выделить группу студентов, чей рост или вес встречаются наиболее часто. Алгоритм решения задачи будет такой. Создадим три списка строк. В цикле будем просматривать таблицу и добавлять в первый список строк значение анализируемого параметра, если его ещё в списке нет. Во второй список будем сохранять фамилии студентов, обладающих данным ростом или весом, а в третьем - в соответствующей строке подсчитывать сколько раз это значение уже встретилось. Вот что должно получиться:
Исходная таблица |
Первый список |
Второй список |
Третий список |
|||||||||||||||
|
Анализ по росту 179 180 175 |
Иванов, Сидоров Петров Ковалёв |
2 1 1 |
Переходя
к новой строке в исходной таблице, мы
анализируем нужный параметр, рост или
вес - ищем в первом списке. Если такого
значения у нас пока нет, мы в каждый
список добавляем по строке, в первый
записываем значение параметра, во второй
- фамилию, а в третий - пишем единичку. А
если такое значение параметра уже есть,
то в соответствующую строку второго
списка добавляем через запятую очередную
фамилию, а в третьем значение в этой
строке увеличиваем на 1. Естественно,
списки строк не должны сортировать
вводимые значения, иначе данные
перепутаются!
Дойдя до конца таблицы,
нам останется в третьем списке найти
строку с максимальным числом, и вывести
как результат содержимое этой строки
второго списка. Получилась такая
программка:
вот процедура подсчёта: procedure TForm1.Button1Click(Sender: TObject); var i, k: Integer; begin Caption:=''; List1.Clear; List2.Clear; List3.Clear; Param:=ComboBox1.ItemIndex+1; for i:=1 to StringGrid1.RowCount-1 do begin k:=List1.IndexOf(StringGrid1.Cells[Param, i]); if k=-1 then begin List1.Add(StringGrid1.Cells[Param, i]); List2.Add(StringGrid1.Cells[0, i]); List3.Add('1'); end else begin List2[k]:=List2[k]+', '+StringGrid1.Cells[0, i]; List3[k]:=IntToStr(StrToInt(List3[k])+1); end; end; k:=0; for i:=0 to List3.Count-1 do if StrToInt(List3[i])>k then k:=StrToInt(List3[i]); for i:=0 to List2.Count-1 do if StrToInt(List3[i])=k then Caption:=Caption+List2[i]+': '+List1[i]+'; '; end;
Сортировка в StringList'е
С помощью StringList можно реализовать интересный вариант сортировки чисел. Хотя StringList сортирует строки, он также будет сортировать и записанные в него в виде строк числа. Естественно, напрямую отсортировать числа таким образом не получится, так как строка, например, '100' будет меньше, чем строка '20', что для чисел 100 и 20, естественно, неверно. Однако достаточно выровнять длину строк добавлением к целой части слева, а к дробной справа пробелов ' ', чтобы сортировка сработала верно. Программисты, создавшие класс TStringList, наделили его очень быстрым алгоритмом сортировки (к тому же реализованным, видимо, с использованием низкоуровневого программирования), чем мы просто не можем не воспользоваться. По сравнению с сортировкой пузырьком, которая 100 000 чисел сортирует за 32 с половиной секунды на моём компе (или 24 сек улучшенный алгоритм), сортировка в StringList'е длится всего 530 мсек! Вот процедура для целых чисел: procedure StringListForSort; var S: TStringList; i, max: Integer; Taim: Int64; begin Taim:=GetTickCount; max:=0; S:=TStringList.Create; for i:=1 to Form1.Grid.RowCount-1 do begin if Length(Form1.Grid.Cells[1, i])>max then max:=Length(Form1.Grid.Cells[1, i]); S.Add(Form1.Grid.Cells[1, i]); end; for i:=0 to S.Count-1 do while Length(S[i])<>max do S[i]:=' '+S[i]; S.Sort; Form1.Caption:='Продолжительность сортировки '+IntToStr(GetTickCount-Taim)+' мсек'; for i:=1 to Form1.Grid.RowCount-1 do Form1.Grid.Cells[1, i]:=Trim(S[i-1]); S.Free; end; Здесь Grid - обычная таблица типа TStringGrid, предварительно заполненная целыми числами. Продолжительность сортировки возвращается в заголовке Формы.
