Автор Тема: Поиск в матрице n*n  (Прочитано 11034 раз)

ilovb

  • Hero Member
  • *****
  • Сообщений: 2538
  • just another nazi test
    • Просмотр профиля
    • Oberon systems
Поиск в матрице n*n
« : Ноябрь 22, 2013, 03:07:30 pm »
Тема перекликается с http://oberspace.dyndns.org/index.php/topic,591.0.html
Яркий пример на тему "ниасилил while (и линейный поиск)"

Выдержка из http://kpolyakov.blogspot.ru/2012/10/break-break.html

Цитировать
Пример 5. Разработать функцию, которая определяет, если ли в квадратной матрице элемент, равный заданному значению.

Будем предполагать, что введен тип данных
type Matrix = array[1..N,1..N] of integer;
Тогда функцию можно написать так:
function Find(const A: Matrix; X: integer): boolean;
var i, j: integer;
begin
  Result := True;
  for i:=1 to N do
    for j:=1 to N do
      if A[i,j] = X then exit;
  Result := False
end;
Здесь оператор exit фактически выполняет роль break для вложенного цикла. С формальной точки зрения у функции два выхода. В общем, «я своим ученикам никогда такое не зачту» — уже слышу я от учителей информатики.

А давайте подумаем, какие альтернативы? Можно вот так:
function Find(const A: Matrix; X: integer): Boolean;
var i, j: integer;
label finish;
begin
  Result := True;
  for i:=1 to N do
    for j:=1 to N do
      if A[i,j] = X then goto finish;
  Result := False;
finish:
end;
Но тут вообще «криминал» — метка и goto! Хотя по сути ничего не изменилось, тот же выход из вложенного цикла.

Конечно, здесь можно использовать исключение:
function Find(const A: Matrix; X: integer): Boolean;
var i, j: integer;
begin
  Result := False;
  try
    for i:=1 to N do
      for j:=1 to N do
        if A[i,j] = X then
          raise Exception.Create('');
  except
    Result := True
  end
end;
Но ведь это далеко не «исключительная ситуация», поэтому по смыслу исключения здесь всё-таки не особо уместны. Кроме того, нужно учитывать, что при обработке исключений выполняется большое число машинных команд, что снижает эффективность программы.

Любителей «чистого» структурного программирования наверняка устроит такой вариант решения:
function Find(A: Matrix; X: integer): Boolean;
var i, j: integer;
begin
  Result := False;
  for i:=1 to N do
    for j:=1 to N do
      if A[i,j] = X then Result := True
end;
Но, к сожалению, по эффективности он не может составить конкуренцию предыдущим, так как в любом случае рассматриваются все N2 элементов массива, даже если элемент A[1,1] равен X.


vlad

  • Hero Member
  • *****
  • Сообщений: 1391
    • Просмотр профиля
Re: Поиск в матрице n*n
« Ответ #1 : Ноябрь 22, 2013, 05:01:46 pm »
Яркий пример на тему "ниасилил while (и линейный поиск)"

И чего? :) Лично я предпочту пройтись по этой матрице std::find. Но если уж слишком много для этого писать (писатель матрицы не позаботился об итераторах), то тогда в отдельную функцию с двумя return.

Цикл Дейкстры напишу только если настроение поглумиться :)

ilovb

  • Hero Member
  • *****
  • Сообщений: 2538
  • just another nazi test
    • Просмотр профиля
    • Oberon systems
Re: Поиск в матрице n*n
« Ответ #2 : Ноябрь 22, 2013, 05:09:50 pm »
Тут не нужен никакой цикл Дейкстры. Обычный лин.поиск. Просто инкремент нужно делать не в одном измерении, а в двух.
PROCEDURE Inc2d(VAR d1, d2: INTEGER);
BEGIN
   INC(d2);
   IF d2 = n THEN
      d2 := 0;
      INC(d1);
   END;
END Inc2d;

i := 0; j := 0;
WHILE (i < n) & (m[i, j] # x) DO
   Inc2d(i, j);
END;
IF i < n THEN
   // нашли
END;

vlad

  • Hero Member
  • *****
  • Сообщений: 1391
    • Просмотр профиля
Re: Поиск в матрице n*n
« Ответ #3 : Ноябрь 22, 2013, 05:43:24 pm »
Тут не нужен никакой цикл Дейкстры. Обычный лин.поиск. Просто инкремент нужно делать не в одном измерении, а в двух.

Не, VAR-параметры это моветон. Тем более для индексов.
ИМХО, у тебя, собственно, и получился завуалированный ЦД.

ilovb

  • Hero Member
  • *****
  • Сообщений: 2538
  • just another nazi test
    • Просмотр профиля
    • Oberon systems
Re: Поиск в матрице n*n
« Ответ #4 : Ноябрь 22, 2013, 05:47:14 pm »
Не, VAR-параметры это моветон. Тем более для индексов.

С каких это пор?  :)

INC() тоже моветон?

ilovb

  • Hero Member
  • *****
  • Сообщений: 2538
  • just another nazi test
    • Просмотр профиля
    • Oberon systems
Re: Поиск в матрице n*n
« Ответ #5 : Ноябрь 22, 2013, 05:50:44 pm »
ИМХО, у тебя, собственно, и получился завуалированный ЦД.

Думаю, что многие циклы "завуалированный ЦД"  ;)
90 процентов чего угодно

vlad

  • Hero Member
  • *****
  • Сообщений: 1391
    • Просмотр профиля
Re: Поиск в матрице n*n
« Ответ #6 : Ноябрь 22, 2013, 06:56:30 pm »
Не, VAR-параметры это моветон. Тем более для индексов.

С каких это пор?  :)

С тех пор как я ознакомился с хаскелем :) Точно не помню, но примерно в то время пришло осознание, что результат должен возвращаться как результат, а не в виде изменяемых аргументов.
А до этого была просто неудовлетворенность существующим синтаксисом C++ (причем в ББ/обероне точно такая же проблема) - в точке вызова не видно, что аргументы передаются по ссылке и будут изменены.

INC() тоже моветон?

Да. ++ намного лучше ;) В крайнем случае  i += 1 :)

P.S. NEW - тоже дурной. Запись p := NEW смотрится намного естественнее.

P.S.S. Не говоря о том, что не сильно оптимизирующий компилятор породит ужасный код для инкремента индексов из твоего примера.
« Последнее редактирование: Ноябрь 22, 2013, 06:59:09 pm от vlad »

vlad

  • Hero Member
  • *****
  • Сообщений: 1391
    • Просмотр профиля
Re: Поиск в матрице n*n
« Ответ #7 : Ноябрь 22, 2013, 07:02:33 pm »
в точке вызова не видно, что аргументы передаются по ссылке и будут изменены.

В C# это фикснули, но для меня было уже поздно :) Для меня, теперь испорченного хаскелем, возврат результата как результата все равно лучше.

ilovb

  • Hero Member
  • *****
  • Сообщений: 2538
  • just another nazi test
    • Просмотр профиля
    • Oberon systems
Re: Поиск в матрице n*n
« Ответ #8 : Ноябрь 22, 2013, 07:12:29 pm »
Ну я пока функциональщиной не заболел.  :) Так что воспринимаю нормально. Помечать не мешало бы, да.
В любом случае Inc2d написана только для иллюстрации схемы цикла.

valexey_u

  • Hero Member
  • *****
  • Сообщений: 3013
    • Просмотр профиля
Re: Поиск в матрице n*n
« Ответ #9 : Ноябрь 22, 2013, 10:59:39 pm »
Многомерные массивы в языке - моветон :-) Не было бы их, и проблемы не было бы.
Y = λf.(λx.f (x x)) (λx.f (x x))

ilovb

  • Hero Member
  • *****
  • Сообщений: 2538
  • just another nazi test
    • Просмотр профиля
    • Oberon systems
Re: Поиск в матрице n*n
« Ответ #10 : Ноябрь 23, 2013, 08:59:52 am »
Матрицы - это моветон. Не было бы их, и проблемы не было бы.

ilovb

  • Hero Member
  • *****
  • Сообщений: 2538
  • just another nazi test
    • Просмотр профиля
    • Oberon systems
Re: Поиск в матрице n*n
« Ответ #11 : Ноябрь 23, 2013, 10:55:25 am »
Чтобы не казалось, что я только других умею дерьмом поливать.
Пожалста: https://code.google.com/p/1c-toolkit/source/browse/lua/cf_tools/cf_inside.lua#108

Прекрасно помню почему так сделал - было лень писать while  :(

Geniepro

  • Hero Member
  • *****
  • Сообщений: 1955
  • Знайте- истина в том, что повторено трижды подряд!
    • Просмотр профиля
Re: Поиск в матрице n*n
« Ответ #12 : Ноябрь 23, 2013, 12:28:13 pm »
i := 0; j := 0;
WHILE (i < n) & (m[i, j] # x) DO
   Inc2d(i, j);
END;
IF i < n THEN
   // нашли
END;

Не понимаю я такого паттерна:
i := 0;
while i < len(arr) and not p(arr[i]) do
  i := i + 1
end;
if i < len(arr) then
  -- нашли!
end;
Всегда делаю так:
i := 0; found := false;
while i < len(arr) and not found do
  if p(arr[i]) then
    found := true
  else
    i := i + 1
end;
if found then
  -- нашли!
end;
или так (учитывая что на паскалях я вапще-то не работаю лет 10):
bool found = false;
for (int i = 0; i < arr.Length && !found; i++)
{
    if (p(arr[i])) found = true;
}
if (found)
{
    // нашли!
}
to iterate is human, to recurse, divine

Салат «рекурсия»: помидоры, огурцы, салат…

ilovb

  • Hero Member
  • *****
  • Сообщений: 2538
  • just another nazi test
    • Просмотр профиля
    • Oberon systems
Re: Поиск в матрице n*n
« Ответ #13 : Ноябрь 23, 2013, 04:00:38 pm »
Из той же оперы: http://ic.asf.ru/~/docs/cpp/cppd_ifstruct.htm

Цитировать
Хотя оператор goto как метод управления программой давно "впал в немилость", он порой оправдывает свое существование. Одним из таких особых случаев является выход из глубоко вложенной процедуры. Рассмотрим, например, следующий фрагмент программы.

int i, j, k;
int stop = 0;

for(i=0; i<100 && istop; i++) {
   for(j=0; j<10 && istop; j+ + ) {
      for(k=0; k<20; k++) {
         // ...
         if(something()) {
            stop = 1;
            break;
         }
      }
   }
}
Переменная stop используется для отмены двух внешних циклов при условии возникновения некоторого программного события. Однако все же лучше достичь того же эффекта с помощью оператора goto.

int i, j, k;

for(i=0; i<100; i++) {
   for(j=0; j<10; j + +) {
      for(k=0; k<20; k++) {
         // . ..
         if(something()) {
            goto done;
         }
      }
   }
}

done: // ...
Как видите, используя оператор goto, можно обойтись без дополнительных затрат ресурсов, которые связаны с повторением проверки значения переменной stop в предыдущем варианте.

Kemet

  • Hero Member
  • *****
  • Сообщений: 587
    • Просмотр профиля
Re: Поиск в матрице n*n
« Ответ #14 : Ноябрь 23, 2013, 04:02:45 pm »
Не понимаю я такого паттерна:
вот здесь-то и пригодился бы цикл-паук