БлогNot. Часто встречающиеся "неправильные" алгоритмы

Часто встречающиеся "неправильные" алгоритмы

Имеем: 10 примеров неправильных (точней, сильно избыточно программируемых) алгоритмов.

Требуется: реализовать алгоритмы так, чтобы их временная сложность соответствовала требуемой в постановке задачи или были проведены иные оптимизации.

Это не каверзные вопросы, и даже не популярные ошибки, это гораздо проще :) Но на основе этих примеров можно увидеть много других распространённых "излишеств" в коде начинающих.

Ответов в этой статье нет, попробуйте найти их сами.

1. Выбор элементов главной диагонали квадратной матрицы A[n,n]

for (int i=0; i<n; i++)
for (int j=0; j<n; j++)
 if (i==j) cout << a[i][j] << “ “;

Очень плохо, что здесь сложность O(n2). Сделайте O(n)

2. Сортировка элементов вектора a[n] по возрастанию

for (int i=0; i<n; i++)
for (int j=0; j<n; j++)
 if (a[i]>a[j]) {
  int t=a[i]; a[i]=a[j]; a[j]=t;
 }

Даже при столь примитивной "пузырькообразной" сортировке, количество операций можно уменьшить как минимум вдвое - от O(n2) до ~O(n2/2), а как?

3. Поиск номера (индекса) максимального элемента в массиве a[n]

int max=a[0], imax=0;
for (int i=1; i<n; i++) 
 if (a[i]>max) {
 max = a[i]; imax=i; 
}

Алгоритм даже проще реализовать без использования двух дополнительных переменных:

#include <iostream>
using namespace std;

int main() {
 const int n = 5;
 int a[n] = {1,4,5,3,2};
 
 int imax = 0;
 for (int i = 0; i < n; i++) if (a[i] > a[imax]) imax = i;
  
 cout << "Index=" << imax;
 cin.get(); return 0;
}

4. Обработка (или вывод) всех элементов симметрической относительно главной диагонали квадратной матрицы A[n,n]

for (int i=0; i<n; i++)
for (int j=0; j<n; j++)
 if (i==j) cout << a[i][j] << " " << a[j][i] << enl;

Как и в задаче 2, можно сократить число шагов вложенного цикла хотя бы вдвое.

5.Определение количества минимальных элементов в целочисленном массиве A[n]

int min=a[0], k=0;
for (int i=1; i<n; i++)
 if (a[i]<min) min=a[i];
for (int i=0; i<n; i++)
 if (a[i]==min) k++;

От O(2*n) легко можно перейти к O(n), выполнив работу за один цикл.

6. Поиск суммы элементов последовательности вида n , 2*n, …, m*n

double s=0; int n=3, m=10;
for (int i=1; i<=m; i++) 
 s+=i*n;

Здесь не нужен цикл вообще, даже сложности O(n). Разумеется, есть решение O(1).

7. Вычисление суммы степенного ряда вида 1+x+x2+…+xn

double sum=0, x=0.5;
for (int i=0; i<=n; i++)
 sum += pow(x,i);

Не стоит так понижать точность расчёта, заново вычисляя всё большую степень от x на каждом шаге цикла.

Попробуйте реализовать алгоритм без необходимости нового полного расчёта степени на каждом шаге.

8. Получение четырёхзначного натурального числа из пары двузначных

int a=12,b=34;
char buf[4];
itoa(a,buf,10);
itoa(b, &buf[2], 10);
cout << buf;

Дополнительный строковый буфер совершенно ни к чему, достаточно арифметики.

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

const int n=4,m=3;
int a[n][m]={
  {10,20,30},
  {15,35,40},
  {20,55,60},
  {40,80,90}
};
 int find = 55;
 bool found = false;
 for (int i=0; i<n; i++)
 for (int j=0; j<m; j++) {
  if (a[i][j]==find) {
   found = true; break;
  }
 }

Плохо, что дополнительная информация об упорядоченности элементов никак не используется при поиске.

Попробуйте решить эту задачу за время, меньшее, чем O(n2), желательно, за логарифмическое.

10. Поиск в массиве натуральных чисел a[n] пары элементов со значениями item1 и item2, расстояние между которыми минимально

const int n=10;
 int a[n] = {
  3,5,10,8,4,12,5,3,0,7
 };
 int item1=3,item2=8,min=n;
 for (int i=0; i<n; i++)
 for (int j=0; j<n; j++) {
  if (a[i]==item1 && a[j]==item2 && abs(i-j)<min) {
      min = abs(i-j);
  }
 }
 cout << min;

Здесь уж сам Бог велел перейти от O(n2) к O(n)

03.06.2018, 23:32 [2395 просмотров]


теги: c++ учебное ошибка алгоритм

К этой статье пока нет комментариев, Ваш будет первым