Re: Алгоритм
- From
- Dmitriy Krylov ()
- To
- Alexander Pashchenko
- Date
- 2002-10-09T05:37:58Z
- Area
- RU.ALGORITHMS
From: "Dmitriy Krylov" <krylov@mail.primorye.ru>
Привет, Alexander!
Вы писали to All on Mon, 07 Oct 2002 10:42:46 +0400:
AP> Задали тут задачку:
AP> Дан массив A[m,n] Известно, что среди его эл-тов всего 2 равны между
AP> собой. Напечатать их индесксы.
AP> Как ее правильно решить.
AP> Я так думаю, что надо проходить по матрице и сравнивать текущий
AP> элемент с запомненным, исключая сам запомненный. И если они равны
AP> вывести индексы.
AP> Но вот тут-то я и запутался.
Ну, если есть память, то можно сделать сделать бинарное дерево, в котором
разместить элементы и соответствующие индексы в порядке прохождения массива.
Например, так:
type
PInedx = ^TIndex;
TIndex = record // Координаты в матрице
X, Y: integer;
end;
PBinaryTree = ^TBinaryTree;
TBinaryTree = record
El: TElem; // А TElem - это тип элементов
Index: TIndex;
Left: PBinaryTree; // Слева - меньшие элементы
Right: PBinaryTree; // Справа - большие
end;
var
Root: PBinaryTree; // Корень дерева;
// <- Tree - поддерево, в которое помещается элемент
// <- El - помещаемый элемент
// <- Index - индекс
// -> результат размещения:
// nil - элемента в дерева не было, элемент помещен
// <>nil - элемент уже есть, результат - ссылка на индекс
function Add(ATree: PBinaryTree; AEl: TElem; AIndex: TIndex): PIndex;
function CreateTree(AEl: TElem; AIndex: TIndex): PTree;
begin
New(Result);
with Result^ do
begin
Left := nil;
Right := nil;
Index := AIndex;
El := AEl;
end;
end;
begin
// Дерево еще не создано, создаем его
if Root = nil then
begin
Root := CreateTree(AEl, AIndex);
Result := nil;
end
else
begin
// Дерево уже создано, поиск элемента в нем...
if AEl = ATree^.El then
begin
// Нашли повторяющийся элемент
Result = @(ATree^.Index);
end
// Иначе размещаем в поддеревьях
else if El > ATree^.El then
begin
// Проходим а правое поддерево
if ATree^.Right = nil then
begin
// Поддерева нет, создаем
ATree^.Right := CreateTree(AEl, AIndex)
Result := nil;
end
else
// Поддерево есть - проходим
Result := Add(ATree^.Right, AEl, AIndex);
end
else
begin
// Проходим в левое поддерево
if ATree^.Left = nil then
begin
// Поддерева нет, создаем
ATree^.Left := CreateTree(AEl, AIndex)
Result := nil;
end
else
// Поддерево есть - проходим
Result := Add(ATree^.Left, AEl, AIndex);
end;
end;
end;
function MakeIndex(AX, AY: integer): TIndex;
begin
Result.X := AX;
Result.Y := AY;
end;
// А теперь обход матрицы
var
I: PIndex; // Индекс найденного элемента
i, j, fi, fj: integer;
begin
Root := nil;
I := nil;
for i := 1 to MaxX do
if I <> nil then
Break
else
for j := 1 to MaxY do
begin
I := Add(Root, Matrix[i, j], MakeIndex(i, j));
if I <> nil then
begin
fi := i; fj := j; // Сохранение индексов
Break;
end;
end;
if I <> nil then
begin
// Распечатка
WriteLn('Первое вхождение:', I^.X, ' ', I^.Y);
WriteLn('Второе вхождение:', fi, fj);
WriteLn('Элемент:', Matrix[fi, fj]);
end
else
begin
WriteLn('Совпадений не найдено');
end;
// Уничтожение дерева...
end;
-----------------------
Вот. А еще, если элементы из маленького множества (TElem = byte), то
вообще - песня:
размещай пройденные элементы в множестве (set), и всё... Можно сделать и для
больших элементов, но тогда придется делать большое бинарное множество.
----------------------
В случае деревьев сложность будет в худшем случае O((MaxX * MaxY) ^ 2) (если
дерево не балансировать), а в среднем O((MaxX * MaxY) * log(MaxX * MaxY)).
Если дерево еще и балансировать, то будет O((MaxX * MaxY) * log(MaxX * MaxY)
^ 2). В C++ STL в классе set<> балансировка включена, так что, если
программируешь на C++, используй этот класс.
В случае, если удастся разместить элементы в бинарном множестве, сложность
будет O(MaxX * MaxY) (т.е. линейно по отношению к размеру матрицы).
Удачи!
__________________________________________________
--{ Dmitriy Krylov aka "Abulafia" }-------------
--{ mailto: krylov@mail.primorye.ru }-------------
--- ifmail v.2.15dev5
* Origin: Demos online service (2:5020/400)