Основы программирования: Фундаментальный курс

Этот курс предназначен для начинающих и охватывает ключевые концепции, необходимые для старта в IT. Вы изучите логику построения алгоритмов, работу с данными и базовые конструкции, применимые в любом языке программирования.

1. Введение в алгоритмическое мышление и логику работы компьютера

Введение в алгоритмическое мышление и логику работы компьютера

Добро пожаловать в курс «Основы программирования: Фундаментальный курс». Вы начинаете путь, который изменит ваш взгляд на взаимодействие с технологиями. Многие считают, что программирование — это просто написание непонятных строк кода на чёрном экране. На самом деле, программирование — это прежде всего способ мышления.

Прежде чем мы напишем нашу первую строчку кода, нам необходимо понять, как «думает» компьютер и как мы должны формулировать свои мысли, чтобы он нас понял. Эта статья посвящена фундаменту, на котором строится всё IT: алгоритмам и логике.

Что такое алгоритм?

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

Алгоритм — это чёткая, конечная последовательность инструкций, выполнение которых приводит к решению поставленной задачи.

Ключевое слово здесь — чёткая. Компьютер, в отличие от человека, не понимает намёков, интонаций или контекста «по умолчанию». Ему нужны предельно точные указания.

Пример бытового алгоритма

Рассмотрим алгоритм «Приготовление чая»:

  • Взять чайник.
  • Налить в чайник воду.
  • Включить чайник.
  • Ждать, пока вода закипит.
  • Положить пакетик чая в кружку.
  • Налить кипяток в кружку.
  • Если мы поменяем местами пункт 3 и 5, результат может не измениться критически. Но если мы поменяем местами пункт 2 и 3 (включим пустой чайник), мы испортим технику. В программировании порядок действий имеет решающее значение.

    !Блок-схема, демонстрирующая последовательность действий и проверку условий при приготовлении чая

    Свойства хорошего алгоритма

    Чтобы алгоритм мог быть выполнен компьютером (или другим исполнителем), он должен обладать следующими свойствами:

    * Дискретность: Процесс решения задачи должен быть разбит на отдельные, завершённые шаги. * Определённость (Детерминированность): Каждый шаг должен быть понятен однозначно. Нельзя написать «добавьте немного сахара». Нужно написать «добавьте 5 грамм сахара». * Результативность: Алгоритм должен приводить к результату за конечное число шагов. Бесконечный цикл без выхода — это ошибка (в большинстве случаев). * Массовость: Алгоритм должен подходить для решения целого класса задач, а не только одной. (Например, алгоритм сложения должен уметь складывать любые два числа, а не только 2 и 2).

    Алгоритмическое мышление

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

    Основные приёмы алгоритмического мышления:

  • Декомпозиция: Разбиение большой сложной задачи на маленькие и простые. Написать «социальную сеть» сложно. Но если разбить это на «создать форму входа», «создать базу данных пользователей», «сделать кнопку лайка», задача становится выполнимой.
  • Абстракция: Отсеивание несущественных деталей. Когда мы пишем программу для навигатора, нам важно расстояние между городами, но не важен цвет асфальта или количество деревьев вдоль дороги.
  • Распознавание паттернов: Поиск схожих элементов в разных задачах. Если вы научились сортировать список книг по алфавиту, вы сможете применить тот же принцип для сортировки списка заказов по дате.
  • Язык компьютера: Двоичная система и Логика

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

    * Есть напряжение (ток идёт). * Нет напряжения (ток не идёт).

    Инженеры договорились обозначать эти состояния цифрами 1 и 0. Это и есть двоичная система счисления (бинарный код).

    Бит и Байт

    * Бит (bit) — минимальная единица информации (0 или 1). * Байт (Byte) — группа из 8 битов. Этого достаточно, чтобы закодировать один символ (например, букву 'A' или цифру '5').

    Любая информация в компьютере — текст, картинка, видео, музыка — это просто огромный набор нулей и единиц.

    Рассмотрим, как число переводится в двоичную систему. В привычной нам десятичной системе мы используем степени числа 10. В двоичной — степени числа 2.

    Где: * — число в двоичной системе. * — цифры числа (биты) слева направо. * — основание системы счисления. * (в степенях) — позиция цифры (разряд), начиная с нуля справа налево. * — итоговое число в десятичной системе.

    !Визуализация двоичного кода через включенные и выключенные лампочки

    Булева логика: Фундамент принятия решений

    Чтобы компьютер мог не просто хранить данные, но и принимать решения (например, «Если пароль верный, пустить пользователя»), используется Булева алгебра. Она оперирует не числами, а логическими значениями: Истина (True) и Ложь (False). В компьютере True соответствует 1, а False — 0.

    Существует три базовые логические операции, из которых строится всё многообразие компьютерной логики:

    1. Логическое И (AND / Конъюнкция)

    Результат истинен только тогда, когда истинны оба условия.

    Пример: Чтобы снять деньги в банкомате, нужно: (Вставить карту) И (Ввести правильный пин-код).

    Таблица истинности для (где — знак операции И):

    | A | B | A AND B | |---|---|---| | 0 | 0 | 0 | | 0 | 1 | 0 | | 1 | 0 | 0 | | 1 | 1 | 1 |

    2. Логическое ИЛИ (OR / Дизъюнкция)

    Результат истинен, когда истинно хотя бы одно из условий (или оба).

    Пример: Я пойду гулять, если (Светит солнце) ИЛИ (У меня есть зонт).

    Таблица истинности для (где — знак операции ИЛИ):

    | A | B | A OR B | |---|---|---| | 0 | 0 | 0 | | 0 | 1 | 1 | | 1 | 0 | 1 | | 1 | 1 | 1 |

    3. Логическое НЕ (NOT / Инверсия)

    Меняет значение на противоположное. Если было Истина, станет Ложь, и наоборот.

    Пример: Если (НЕ Дождь), то идем гулять.

    Таблица истинности для (где — знак операции НЕ):

    | A | NOT A | |---|---| | 0 | 1 | | 1 | 0 |

    !Схематичное изображение базовых логических вентилей, используемых в электронике

    Как это работает вместе?

    Процессор компьютера состоит из миллиардов микроскопических транзисторов, которые собираются в логические вентили (AND, OR, NOT). Комбинируя эти вентили, инженеры создают схемы, способные складывать числа, хранить память и выполнять команды.

    Когда вы пишете код на языке программирования (например, Python, Java или C++), происходит следующее:

  • Написание: Вы пишете алгоритм на понятном человеку языке программирования.
  • Компиляция/Интерпретация: Специальная программа переводит ваш код в набор машинных инструкций (нули и единицы).
  • Выполнение: Процессор получает эти инструкции, прогоняет их через свои логические схемы и выдает результат.
  • Заключение

    Сегодня мы узнали, что программирование начинается не с клавиатуры, а с головы. Мы разобрали понятие алгоритма, научились видеть структуру задач через декомпозицию и заглянули внутрь «мозга» компьютера, где царят нули, единицы и строгая логика.

    В следующей статье мы перейдем от теории к практике и узнаем, что такое переменные и типы данных — кирпичики, из которых строится любая программа.

    2. Переменные, типы данных и базовые операции

    Переменные, типы данных и базовые операции

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

    Сегодня мы разберемся, как компьютер хранит информацию, почему для него число «5» и символ «5» — это совершенно разные вещи, и как выполнять базовые операции над данными.

    Что такое переменная?

    Представьте, что вы переезжаете. У вас есть куча вещей, и чтобы не потерять их, вы раскладываете их по коробкам. На каждой коробке вы пишете маркером название: «Книги», «Посуда», «Одежда».

    В программировании переменная — это и есть такая именованная «коробка» в оперативной памяти компьютера, в которой хранится какое-то значение (данные).

    !Визуальная метафора переменной как коробки с именем, хранящей значение.

    Создание переменной и присваивание

    Чтобы создать переменную, нам нужно придумать ей имя и положить в неё значение. Этот процесс называется присваиванием. В большинстве языков программирования для этого используется знак равенства =.

    Важно запомнить: в программировании знак = означает не «равно» (как в математике), а «присвоить значение справа переменной слева».

    Пример кода:

    Здесь мы создали переменную с именем score и положили в неё число 100. Затем создали переменную name и положили в неё текст «Alex».

    Правила именования

    Имя переменной (идентификатор) — это ваш способ обратиться к данным. Чтобы компьютер вас понял, нужно соблюдать правила:

  • Без пробелов: Нельзя назвать переменную my score. Используйте my_score или myScore.
  • Латиница: Хотя некоторые языки позволяют использовать кириллицу, стандартом считается английский язык.
  • Понятный смысл: Имя x ничего не говорит о содержимом. Имя user_age (возраст пользователя) сразу объясняет суть.
  • Типы данных

    Для человека надпись «15» на бумаге может означать количество яблок, номер дома или просто набор черточек. Мы понимаем смысл из контекста. Компьютер контекста не понимает. Ему нужно чётко знать, что именно лежит в переменной, чтобы понимать, сколько памяти выделить и какие операции можно выполнять.

    Это определяется типом данных.

    Рассмотрим основные фундаментальные типы, которые есть почти во всех языках программирования.

    1. Целые числа (Integer)

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

    * Примеры: 0, 5, -10, 42. * Обозначение в языках: int.

    2. Вещественные числа (Float / Double)

    Числа с плавающей точкой (дробные). Используются для точных измерений: вес, рост, координаты, деньги (с оговорками).

    * Примеры: 3.14, -0.01, 2.5. * Обозначение в языках: float, double.

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

    3. Строки (String)

    Текстовая информация. Строка — это последовательность символов. Чтобы компьютер отличил строку от имени переменной или команды, строку всегда заключают в кавычки (одинарные или двойные).

    * Примеры: "Hello", 'A', "123" (это текст, а не число!). * Обозначение в языках: str, string.

    4. Логический тип (Boolean)

    Самый простой тип данных, который мы затрагивали в прошлой статье про логику. Имеет всего два возможных значения.

    * Значения: True (Истина/1) и False (Ложь/0). * Обозначение в языках: bool.

    !Структурная схема основных типов данных.

    Почему типы данных важны?

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

    Рассмотрим пример операции сложения +:

    * Если сложить два числа: 5 + 5 результат будет 10. * Если сложить две строки: "5" + "5" результат будет "55".

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

    Базовые операции

    Когда данные сохранены в переменных, мы можем ими манипулировать. Операции делятся на несколько групп.

    Арифметические операции

    Это стандартная математика. Допустим, у нас есть переменные a = 10 и b = 3.

    | Операция | Символ | Пример | Результат | Описание | | :--- | :---: | :--- | :--- | :--- | | Сложение | + | a + b | 13 | Сумма чисел | | Вычитание | - | a - b | 7 | Разность чисел | | Умножение | | a b | 30 | Произведение | | Деление | / | a / b | 3.33... | Результат деления (часто float) | | Остаток от деления | % | a % b | 1 | 10 делится на 3 трижды, остаток 1 |

    Операция остаток от деления (%) очень важна в программировании. Она часто используется, чтобы проверить, является ли число четным (остаток от деления на 2 равен 0) или для зацикливания процессов.

    Рассмотрим пример использования переменных в формуле. Допустим, нам нужно вычислить площадь прямоугольника.

    Где — площадь прямоугольника, — длина стороны, — ширина стороны.

    В коде это выглядело бы так:

    Операции сравнения

    Эти операции всегда возвращают логический тип (True или False). Они нужны для принятия решений (о чем мы поговорим в следующих статьях).

    * > (больше), < (меньше) * >= (больше или равно), <= (меньше или равно) * == (равно). Внимание! Два знака равно используются для проверки равенства, так как один знак = занят под присваивание. * != (не равно).

    Логические операции

    Мы разбирали их в прошлой статье: AND (и), OR (или), NOT (не). Они позволяют комбинировать условия.

    Статическая и Динамическая типизация

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

    Статическая типизация (C++, Java, Go)

    Здесь вы должны строго объявить тип переменной при её создании, и этот тип нельзя изменить. Это похоже на то, если бы вы купили контейнер, на котором на заводе выгравировано «ДЛЯ ЯИЦ». Вы не можете положить туда молоко.

    Пример (язык Java):

    Динамическая типизация (Python, JavaScript, PHP)

    Здесь тип переменной определяется автоматически в момент присваивания значения. Переменная — это просто наклейка, которую можно переклеить на любой предмет.

    Пример (язык Python):

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

    Изменение значений переменных

    Переменные называются так, потому что их значение может меняться в ходе выполнения программы. Очень частая операция — увеличение значения переменной на основе её текущего состояния.

    Представьте счетчик жизней в игре:

    Где — новое количество жизней, — текущее количество жизней, — величина урона.

    В программировании это записывается так:

    Компьютер сначала вычисляет правую часть (3 - 1), получает 2, и затем записывает этот результат обратно в переменную lives.

    Заключение

    Сегодня мы заложили первый камень в фундамент написания кода. Мы узнали:

  • Переменные — это именованные ячейки памяти для хранения данных.
  • Типы данных определяют, что именно мы храним (числа, строки, логику) и что с этим можно делать.
  • Операции позволяют нам создавать новые данные из уже имеющихся.
  • В следующей статье мы оживим наши программы. Мы научимся управлять потоком выполнения кода с помощью условных операторов, чтобы программа могла принимать решения в зависимости от данных, которые мы сегодня научились хранить.

    3. Управление потоком выполнения: условные конструкции и циклы

    Управление потоком выполнения: условные конструкции и циклы

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

    Сегодня мы превратим нашу «прямую дорогу» в сложную транспортную сеть. Мы научимся заставлять программу принимать решения и выполнять рутинную работу за нас. Это называется управление потоком выполнения (Control Flow).

    Условные конструкции: Искусство выбора

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

    В программировании за принятие решений отвечают условные операторы. Самый главный из них — if (если).

    Оператор if

    Конструкция if проверяет истинность условия. Если условие верно (равно True), то блок кода внутри выполняется. Если нет — пропускается.

    Синтаксис (на примере Python-подобного псевдокода):

    Здесь программа проверяет переменную password. Если она совпадает со строкой "secret123", то на экран выводится сообщение. Если пароль другой, программа просто пойдет дальше, ничего не сделав.

    Оператор else (Иначе)

    Часто нам нужно не просто пропустить действие, а выполнить альтернативное. Для этого используется else.

    Теперь у нас есть развилка: программа пойдет либо по первому пути, либо по второму. Одновременно оба варианта сработать не могут.

    !Блок-схема работы условной конструкции if-else

    Множественный выбор: else if (elif)

    Жизнь редко бывает черно-белой. Иногда вариантов больше двух. Например, светофор:

  • Если красный — стой.
  • Если желтый — готовься.
  • Если зеленый — иди.
  • В программировании для этого используется конструкция else if (в Python сокращается до elif).

    Компьютер проверяет условия по очереди сверху вниз. Как только он находит первое верное условие (True), он выполняет соответствующий блок и выходит из всей конструкции. Остальные проверки игнорируются.

    Вложенные условия

    Один if может находиться внутри другого. Это называется вложенностью.

    Хотя вложенность — мощный инструмент, злоупотреблять ею не стоит. Если вложений слишком много, код становится похож на «лесенку» и его очень трудно читать.

    Циклы: Автоматизация рутины

    Представьте, что вам нужно вывести на экран фразу «Я не буду кидаться мелом» 100 раз. Вы можете скопировать строчку кода 100 раз, но это долго и неэффективно. А если нужно сделать это миллион раз?

    Для многократного повторения действий используются циклы.

    Цикл while (Пока)

    Этот цикл работает до тех пор, пока условие остается истинным. Он похож на if, который повторяет сам себя.

    Где — это переменная-счетчик, а — граничное условие.

    Пример:

    Как это работает пошагово:

  • Проверяем: 0 меньше 5? Да. Печатаем «Привет!». Увеличиваем count до 1.
  • Проверяем: 1 меньше 5? Да. Печатаем «Привет!». Увеличиваем count до 2.
  • ... и так далее ...
  • Проверяем: 5 меньше 5? Нет (Ложь). Цикл завершается.
  • Опасность: Бесконечный цикл

    Если вы забудете строчку count = count + 1, переменная count всегда будет равна 0. Условие 0 < 5 всегда будет истинным. Программа зависнет, бесконечно печатая «Привет!», пока вы принудительно её не остановите или пока не закончится память компьютера.

    !Циклический процесс выполнения кода с проверкой условия

    Цикл for (Для)

    Цикл for используется, когда мы точно знаем, сколько раз нужно повторить действие, или когда нам нужно перебрать набор элементов (например, список студентов).

    В большинстве языков это выглядит как перебор диапазона чисел.

    Переменная i (от слова index или iterator) автоматически меняет свое значение на каждом шаге: 0, 1, 2, 3, 4. Программисту не нужно вручную увеличивать её, как в while.

    Управление внутри циклов

    Иногда нам нужно нарушить стандартный ход цикла. Для этого есть два специальных слова-команды:

    1. break (Прервать)

    Команда break немедленно останавливает выполнение цикла, даже если условие всё еще истинно.

    Пример: Мы ищем книгу в стопке. Как только нашли нужную, нам нет смысла перебирать остальные — мы используем break.

    2. continue (Продолжить)

    Команда continue прерывает только текущую итерацию (круг) цикла и сразу переходит к следующей, пропуская весь код, который написан ниже continue.

    Пример: Мы считаем сумму чисел, но хотим пропустить все отрицательные числа.

    В этом примере фраза «Обрабатываем число» не напечатается для -5 и -1.

    Как выбрать между while и for?

    Новички часто путаются, какой цикл использовать. Вот простое правило:

    * Используйте for, если вы знаете количество повторений (например, «сделать 10 раз») или перебираете конечный набор данных (все буквы в слове). * Используйте while, если вы не знаете точного числа повторений, но знаете условие остановки (например, «бежать, пока не устану» или «ждать, пока пользователь не нажмет кнопку»).

    Практический пример: Банкомат

    Давайте объединим переменные, условия и циклы в логике работы упрощенного банкомата.

  • У нас есть переменная balance (баланс).
  • Мы спрашиваем пин-код в цикле while (даем 3 попытки).
  • Если пин верный, используем if, чтобы проверить, хватает ли денег для снятия.
  • Если денег хватает, вычитаем сумму и выдаем наличные.
  • Без условных конструкций банкомат выдавал бы деньги даже при нулевом балансе. Без циклов пользователю пришлось бы перезагружать банкомат после каждой ошибки ввода пин-кода.

    Заключение

    Условные конструкции и циклы — это скелет логики любой программы. Благодаря им код становится гибким и способным обрабатывать огромные объемы данных без участия человека.

    * if / else позволяют программе выбирать путь. * while / for позволяют программе повторять действия. * break / continue дают тонкий контроль над повторениями.

    В следующей статье мы разберем тему Функций. Мы узнаем, как упаковывать сложные алгоритмы в компактные «черные ящики», чтобы использовать их снова и снова, не переписывая код.

    4. Функции, модульность и повторное использование кода

    Функции, модульность и повторное использование кода

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

    Представьте, что вы пишете программу для управления «умным домом». Вам нужно включать свет в гостиной, на кухне, в спальне и в коридоре. Код для включения лампочки занимает 5 строк. Если вы скопируете эти 5 строк для каждой комнаты, ваш файл превратится в бесконечное полотно повторяющегося текста. А если вы захотите изменить логику включения (например, добавить плавное разгорание)? Вам придется искать и менять код в четырех разных местах.

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

    Что такое функция?

    В математике функция — это закон, по которому каждому значению ставится в соответствие значение . Например:

    Где: * — имя функции. * — аргумент (входное значение). * — правило преобразования.

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

    !Функция как «черный ящик»: входные данные превращаются в результат.

    Зачем нужны функции?

  • Принцип DRY (Don't Repeat Yourself): «Не повторяйся». Это золотое правило программирования. Если вы пишете один и тот же код дважды — это повод создать функцию.
  • Декомпозиция: Разбиение большой сложной задачи на маленькие и простые. Проще написать функции «Закипятить воду», «Заварить чай», «Налить в чашку», чем держать в голове весь процесс сразу.
  • Читаемость: Код cook_dinner() (приготовить ужин) понятнее, чем 50 строк инструкций по нарезке овощей и жарке мяса.
  • Анатомия функции

    Давайте посмотрим, из чего состоит функция. Синтаксис может отличаться в разных языках (Python, C++, Java), но структура везде одинакова.

    1. Объявление и Имя

    Сначала мы говорим компьютеру: «Я создаю новую команду». Мы даем ей имя. Имя должно быть глаголом, так как функция — это действие. Хорошие имена: calculate_tax (посчитать налог), send_email (отправить письмо). Плохие имена: data, func1, do_it.

    2. Параметры (Аргументы)

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

    3. Тело функции

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

    4. Возвращаемое значение (Return)

    Это результат работы функции, который она отдает обратно программе.

    Рассмотрим пример на псевдокоде (похожем на Python):

    Здесь: * def — ключевое слово (definition), означающее начало функции. * greet — имя функции. * name — параметр (переменная, в которую попадет имя). * return — команда вернуть результат.

    Теперь, чтобы использовать эту функцию, мы её вызываем:

    Параметры и Аргументы: В чем разница?

    Эти слова часто используют как синонимы, но технически разница есть:

    Параметр — это переменная, указанная при создании* функции (в примере выше — name). Это как слот в тостере. Аргумент — это конкретное значение, которое мы передаем при вызове* функции (в примере выше — "Алекс"). Это хлеб, который мы кладем в слот.

    Return против Print

    Новички часто путают вывод на экран (print) и возврат значения (return). Это критически важное различие.

    * Print — это просто «крикнуть» результат. Программа показывает текст пользователю, но сама программа этот результат «забывает» сразу после вывода. С этим результатом нельзя производить дальнейшие математические действия. * Return — это передача данных. Функция тихо отдает результат тому месту в коде, откуда её вызвали. Этот результат можно сохранить в переменную и использовать дальше.

    Представьте, что вы просите повара приготовить пиццу. * Если повар использует print, он просто показывает вам пиццу и сразу выбрасывает её. Вы её видели, но съесть не можете. * Если повар использует return, он отдает пиццу вам в руки. Вы можете её съесть, положить в холодильник или подарить другу.

    Пример:

    Если бы мы использовали print внутри add, переменная result осталась бы пустой, и умножить её на 2 было бы невозможно.

    Область видимости (Scope)

    Что происходит в Вегасе, остается в Вегасе. То же самое касается функций.

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

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

    !Концепция локальной и глобальной области видимости.

    Модульность и Библиотеки

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

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

    Пример использования готового модуля:

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

    Рекурсия: Функция вызывает сама себя

    Иногда для решения задачи функции удобно вызвать саму себя. Это называется рекурсия.

    Классический пример — вычисление факториала. Факториал числа (обозначается ) — это произведение всех натуральных чисел от 1 до .

    Формула факториала:

    Где: * — факториал числа. * — само число. * — знак умножения.

    Но математически это можно записать и так:

    Где: * — факториал текущего числа. * — текущее число. * — факториал предыдущего числа.

    То есть, чтобы найти факториал 5, нужно 5 умножить на факториал 4. А для факториала 4 нужно 4 умножить на факториал 3. И так до тех пор, пока мы не дойдем до 1.

    В коде это выглядит элегантно:

    Рекурсия — мощный, но опасный инструмент. Если забыть условие выхода (в примере это if n == 1), функция будет вызывать себя бесконечно, пока не закончится память (Stack Overflow).

    Заключение

    Сегодня мы сделали огромный шаг вперед. Мы перешли от написания простых инструкций к проектированию архитектуры программы.

    Мы узнали:

  • Функции помогают избегать повторений и делают код чище.
  • Параметры позволяют настраивать работу функции.
  • Return возвращает результат для дальнейшего использования.
  • Область видимости защищает переменные от конфликтов.
  • В следующей статье мы разберем, как хранить большие объемы данных. Мы поговорим о структурах данных: массивах и списках, которые позволят нам обрабатывать не одну переменную, а тысячи значений одновременно.

    5. Основы структур данных: массивы и списки

    Основы структур данных: массивы и списки

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

    Создавать тысячи переменных с именами student1, student2, student3 ... student1000 — это не просто неудобно, это делает программирование невозможным. Нам нужен способ хранить группы данных под одним именем.

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

    Что такое структура данных?

    Если переменная — это коробка, то структура данных — это способ организации этих коробок на складе. От того, как именно мы их расставим (в ряд, стопкой, по алфавиту), зависит, насколько быстро мы сможем найти нужную вещь или добавить новую.

    Самая базовая и древняя структура данных — это массив.

    Массив (Array)

    Представьте себе улицу, на которой стоят одинаковые дома. У каждого дома есть номер: 0, 1, 2, 3 и так далее. Дома стоят плотно друг к другу, без промежутков.

    Массив — это набор элементов одного типа, расположенных в памяти компьютера строго друг за другом.

    Ключевые свойства массива:

  • Фиксированный размер: При создании массива мы обычно должны сказать компьютеру: «Мне нужно место для 10 чисел». Компьютер выделяет этот кусок памяти, и расширить его потом «бесплатно» нельзя.
  • Один тип данных: В классическом массиве нельзя хранить в первой ячейке число, а во второй — строку (хотя современные высокоуровневые языки умеют обходить это ограничение).
  • Индексация: Доступ к элементам осуществляется по номеру (индексу).
  • !Визуализация массива в памяти как непрерывного блока ячеек с индексами.

    Почему программисты считают с нуля?

    Новички часто удивляются: почему первый элемент массива имеет индекс 0, а не 1? Это связано с тем, как компьютер находит данные в памяти.

    Индекс — это не «номер по порядку», а смещение (отступ) от начала массива.

    Представьте, что начало массива находится по адресу памяти 1000. Размер одного числа — 4 байта.

    Чтобы найти элемент с индексом , компьютер использует простую формулу:

    Где: * — искомый адрес ячейки памяти. * — базовый адрес (начало массива). * — индекс элемента. * — размер одного элемента в байтах.

    Если мы хотим взять самый первый элемент, нам не нужно никуда отступать от начала. Смещение равно 0. Поэтому индекс равен 0.

    Если бы мы начинали считать с 1, компьютеру пришлось бы каждый раз выполнять лишнее вычитание: , что замедляло бы работу старых компьютеров.

    Доступ к элементам

    Благодаря формуле выше, массив обладает суперспособностью: мгновенный доступ к любому элементу. Неважно, хотите вы взять 1-й элемент или 1000000-й — компьютеру требуется одинаковое время, чтобы вычислить адрес. В теории алгоритмов это называется сложностью .

    Пример на псевдокоде:

    Динамические массивы и Списки

    Классические массивы имеют недостаток: они жесткие. Если вы создали массив на 5 мест, а пришел шестой ученик, вам придется:

  • Создать новый массив большего размера (например, на 10 мест).
  • Скопировать все данные из старого массива в новый.
  • Добавить нового ученика.
  • Удалить старый массив.
  • В современных языках (Python, JavaScript, Java) эту проблему решают Динамические массивы (в Python они называются просто list — список).

    Они умеют автоматически расширяться, когда место заканчивается. Для программиста это выглядит как магия: вы просто добавляете элементы, а язык сам заботится о памяти.

    Основные операции со списками

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

    #### 1. Добавление в конец (Append) Самая быстрая операция. Мы просто дописываем элемент в свободную ячейку.

    #### 2. Вставка в середину (Insert) Это дорогая операция. Представьте, что люди стоят в очереди. Если вы хотите встать вторым, всем, кто стоит за вами, придется сделать шаг назад, чтобы освободить место.

    Компьютеру приходится сдвигать все элементы, находящиеся справа от места вставки, на одну позицию.

    #### 3. Удаление (Delete) То же самое, что и вставка, только наоборот. Если человек уходит из очереди, все остальные делают шаг вперед, чтобы закрыть дыру.

    #### 4. Перебор (Итерация) Мы можем пройтись по всем элементам списка с помощью цикла for, который мы изучили в прошлой статье.

    Многомерные массивы (Матрицы)

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

    Для этого используются многомерные массивы (массивы массивов). Самый простой вариант — двумерный массив (матрица).

    Представьте его как таблицу с рядами (rows) и колонками (columns).

    !Двумерный массив: доступ к данным осуществляется по двум координатам.

    Чтобы получить данные, нам нужно указать два индекса: [строка][столбец].

    Строки — это тоже массивы

    Интересный факт: текст (String), с которым мы работали ранее, технически является массивом символов. Именно поэтому во многих языках вы можете обращаться к буквам в слове так же, как к элементам списка.

    Когда использовать массивы и списки?

    Используйте их, когда:

  • У вас есть набор однотипных данных (список пользователей, координаты точек, история транзакций).
  • Вам важен порядок элементов.
  • Вам нужно часто обращаться к элементам по их порядковому номеру.
  • Заключение

    Массивы и списки — это «рабочие лошадки» программирования. 99% программ используют их для хранения данных в оперативной памяти. Мы узнали, что:

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

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