Эти шаблоны позволяют автоматизировать работу с последовательными данными.

Все языки программирования предоставляют средства для последовательного хранения данных. В некоторых языках для этой цели используются массивы. Некоторые языки используют список терминов, а не массив. Некоторые языки предоставляют как массивы, так и другой тип последовательного сбора данных - вектор (C ++) или ArrayList (Java и C #). Для упрощения я назову структуру данных, используемую для хранения последовательных данных, коллекцией.

В этой статье будут продемонстрированы шесть шаблонов программ, которым должен научиться начинающий программист, чтобы принимать решения о том, как работать с этими коллекциями в более автоматическом режиме. Я покажу вам псевдокод шаблона, а затем приведу два или три примера на разных языках, чтобы вы могли увидеть, как используется шаблон. Иногда будет несколько примеров псевдокода, когда может быть несколько способов использования шаблона, например, при добавлении данных в массив вместо добавления данных в вектор.

Заполните массив (или список, или вектор и т. Д.)

Этот первый шаблон программы используется при получении данных от пользователя и их хранении в коллекции, чтобы упростить работу с данными. Например, если я хочу собрать оценки за тест и отсортировать их от высшей к низшей, это намного проще сделать, когда данные находятся в коллекции, чем если бы я пытался отсортировать независимые переменные.

Вот псевдокод для заполнения массива данными:

Объявите массив с размером
Установите для переменной индекса массива значение 0
Пока есть дополнительные данные:
Прочтите значение
Сохраните значение в массиве по индексу position
Увеличить позицию индекса на 1

Вот псевдокод для заполнения вектора C ++ данными:

Объявите вектор с типом данных
Пока есть дополнительные данные:
Прочтите значение
Верните значение в вектор

Вот псевдокод для заполнения списка Python данными:

Объявите список
Пока есть дополнительные данные:
Прочтите значение
Добавьте значение в список

Вот пример заполнения массива в JavaScript:

let grades = new Array();
const NUM_GRADES = 5;
for (let i = 0; i < NUM_GRADES; i++) {
  putstr("Enter a grade: ");
  let grade = parseInt(readline())
  grades[i] = grade;
}

А вот пример заливки вектора на C ++:

#include <iostream>
#include <vector>
using namespace std;
int main()
{
  vector<int> grades;
  const int NUM_GRADES = 5;
  int grade;
  for (int i = 0; i < NUM_GRADES; i++) {
    cout << "Enter a grade: ";
    cin >> grade;
    grades.push_back(grade);
  }
return 0;
}

Вот еще один пример на Python, использующий контрольное значение для управления вводом:

grades = []
grade = int(input(Enter a grade: "))
while grade != -1:
  grades.append(grade)
  grade = int(input("Enter a grade: "))

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

Обработка каждого элемента

После того, как вы заполнили коллекцию данными, вам нужно будет выполнить некоторый тип вычислений с этими данными. Часто бывает необходимо получить доступ к каждому элементу коллекции, например, добавить его к сумме для определения среднего значения, или отсортировать данные по порядку, или даже просто отобразить данные на экране. Для этих целей используется шаблон «Обработка каждого элемента».

Существуют разные примеры псевдокода для этого шаблона в зависимости от используемого вами языка и способа доступа к данным. Большинство языков позволяют получить доступ к коллекции с помощью индекса, но многие языки также позволяют использовать более простой метод, позволяющий языку выполнять индексацию. Я продемонстрирую все эти методы и расскажу, когда их использовать.

Во-первых, вот псевдокод для обработки каждого элемента с помощью индексации:

Для индекса от 0 до длины коллекции минус 1:
Обработать элемент по индексу

Вот пример использования этого псевдокода в JavaScript, где массив инициализируется при объявлении:

let grades = new Array(71, 88, 91);
for (let i = 0; i < grades.length; i++) {
  putstr(grades[i] + " ");
}

Это похоже на другие языки, использующие синтаксис в стиле C. В Python цикл for выглядит немного иначе:

grades = [71, 88, 91]
for i in range(0, len(grades)):
  print(grades[i], end=" ")

Индексированный доступ к коллекции может привести к ошибкам, если вы случайно попытаетесь получить доступ к элементу коллекции, который находится за пределами коллекции. Чтобы исправить это, в большинстве языков теперь есть конструкция, которая позволяет вам получить доступ к каждому элементу коллекции без использования индекса. Обычно это называется циклом for-each, причем каждый язык реализует этот тип цикла по-разному.

Однако мы можем написать псевдокод в общем виде и продемонстрировать его использование на разных языках. Вот:

Для каждого элемента в коллекции:
Обработать элемент

Вот как цикл for-each используется в C ++:

int main()
{
  const int NUM_GRADES = 3;
  int grades[NUM_GRADES] = {71, 88, 91};
  for (int grade : grades) { // range for loop
    cout << grade << " ";
  }
  return 0;
}

Это работает одинаково, если данные хранятся в векторе.

В JavaScript правильный цикл for для использования в массиве - это цикл for-of. Вот программа, которая вычисляет среднее значение оценок в массиве с помощью цикла for-of:

let grades = new Array(71, 88, 91);
let total = 0;
for (const grade of grades) {
  total += grade;
}
let average = total / grades.length;
print("Average:", average);

По общему мнению гуру программирования, каждый раз, когда вы обращаетесь к каждому элементу коллекции, например к массиву или вектору, если этот тип цикла доступен в вашем языке программирования, следует использовать цикл для каждого типа. Использование цикла для каждого типа помогает избежать синтаксических ошибок (большинство языков) или логических ошибок (C ++) в языках, которые разрешают доступ к памяти за пределами коллекции.

Искать в коллекции

Этот программный шаблон предназначен для линейного или последовательного поиска, когда поиск начинается в начале коллекции и заканчивается, когда поиск находит искомый элемент, или поиск достигает конца коллекции, не находя искомого элемента.

Как и шаблон Обработка каждого элемента, этот шаблон можно использовать с индексированным циклом или с циклом для каждого типа. Вот псевдокод проиндексированного шаблона:

получить значение для поиска
установить для индекса значение 0
для индекса ‹длина коллекции
, если коллекция [индекс] равна значению для поиска
вернуть успех
если в конце сбора
сообщить об ошибке

Вот пример работы этого шаблона в Python, где определена функция для поиска значения в списке:

def search(coll, value):
  for i in range(0, len(coll)):
    if coll[i] == value:
      return True
  return False

from random import seed
from random import randint
seed(1)
grades = []
for i in range(10):
  grades.append(randint(50,100))
print(grades)
value = int(input("Enter search value: "))
if search(grades, value):
  print(value,"is in grades.")
else:
  print(value,"is not in grades.")

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

Программный шаблон для выполнения поиска для каждого подобен проиндексированному шаблону:

получить значение для поиска
начать в начале коллекции
если текущий элемент равен искомому значению
вернуть успех
если в конце коллекции
вернуть сбой

Вот пример этого шаблона, используемого в C ++, с использованием вектора:

#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
using namespace std;
bool search(vector<int> vec, int value){
  for (int number : vec) {
    if (number == value) {
      return true;
    }
  }
  return false;
}

int main()
{
  srand(time(0));
  vector<int> numbers;
  for (int i = 1; i <= 10; i++) {
    numbers.push_back(rand() % 100 + 1);
  }
  for (int number : numbers) {
    cout << number << " ";
  }
  cout << endl;
  int value;
  cout << "Enter a value to search for: ";
  cin >> value;
  if (search(numbers, value)) {
    cout << value << " is in numbers." << endl;
  }
  else {
    cout << value << " is not in numbers." << endl;
  }
  return 0;
}

Вот подсказка по C ++. Вы не можете использовать диапазон для цикла в функции, если аргумент коллекции является массивом. В этой ситуации можно использовать только вектор. Вы можете перемещаться по массиву с диапазоном для цикла в основной функции, вы просто не можете использовать этот тип цикла в функции, возвращающей значение.

Шаблоны программ и опыт программирования

Один из ключей к тому, чтобы стать экспертом в области программирования, - это изучение различных шаблонов программ, которые используются для решения проблем. Подобно тому, как гроссмейстеры становятся такими, изучая известные позиции шахматной доски, научившись быстро распознавать, когда следует использовать шаблон программы, и зная, как использовать его эффективно, вы сможете стать гроссмейстером в программировании.