Основы С++ (массивы, указатели). Задачи с массивами

37
Основы программирования на C++ Максименкова Ольга Вениаминовна Старший преподаватель Департамента программной инженерии Факультета компьютерных наук © Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ ФКН НИУ ВШЭ 1 28.06.2016

Transcript of Основы С++ (массивы, указатели). Задачи с массивами

Page 1: Основы С++ (массивы, указатели). Задачи с массивами

Основы программирования на C++

Максименкова Ольга Вениаминовна

Старший преподаватель Департамента программной инженерии Факультета компьютерных наук

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ128.06.2016

Page 2: Основы С++ (массивы, указатели). Задачи с массивами

Цели занятия

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ2

Рассмотреть

• Массивы в языке С++

• Указатели в языке С++

• Связь между массивами и указателями

• Массивы и указатели как параметры функций

• Некоторые алгоритмы сортировки массивов

Попрактиковаться

• В реализации алгоритмов на языке C++

28.06.2016

Page 3: Основы С++ (массивы, указатели). Задачи с массивами

Производные типы данныхМассивы

Указатели

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ328.06.2016

Page 4: Основы С++ (массивы, указатели). Задачи с массивами

Массивы

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ4

int arr[]; // нельзя определить массив без размера

тип имя_массива[константое_выражение]

int arr[10]; // определён массив из 10 элементов

int arr[10]; // определён массив из 10 элементовfor (int i = 0; i < 10; i++) {cout << arr[i] << " ";cout << arr + i << "\n";

}

-858993460 000000308B0FFCA8-858993460 000000308B0FFCAC-858993460 000000308B0FFCB0-858993460 000000308B0FFCB4-858993460 000000308B0FFCB8-858993460 000000308B0FFCBC-858993460 000000308B0FFCC0-858993460 000000308B0FFCC4-858993460 000000308B0FFCC8-858993460 000000308B0FFCCC

28.06.2016

Page 5: Основы С++ (массивы, указатели). Задачи с массивами

Инициализация элементов массива

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ5

int arr[10];for (int i = 0;i < 10;i++) {

arr[i] = 0;cout << arr[i] << " ";

}

short shArr[10];shArr[0] = 1;for (int i = 1; i < 10; i++) {shArr[i] = shArr[i-1]*i;cout << i << " " << shArr[i] << " ";cout << shArr + i << "\n";

}

0 00000019F88FFA380 00000019F88FFA3C0 00000019F88FFA400 00000019F88FFA440 00000019F88FFA480 00000019F88FFA4C0 00000019F88FFA500 00000019F88FFA540 00000019F88FFA580 00000019F88FFA5C

1 1 000000A7C63AFA9A2 2 000000A7C63AFA9C3 6 000000A7C63AFA9E4 24 000000A7C63AFAA05 120 000000A7C63AFAA26 720 000000A7C63AFAA47 5040 000000A7C63AFAA68 -25216 000000A7C63AFAA89 -30336 000000A7C63AFAAA

Переполнение типа

28.06.2016

Page 6: Основы С++ (массивы, указатели). Задачи с массивами

Темная сторона скрывает все. Невозможно будущее предвидеть нам ©

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ6

C++ Accesses an Array out of bounds gives no error, why?[http://stackoverflow.com/questions/1239938/c-accesses-an-

array-out-of-bounds-gives-no-error-why]

int arr[5]; // определён массив из 5 элементов

// заполним массив десятьюfor (int i = 0; i < 10; i++) {arr[i] = i;cout << arr[i] << " ";

}system("pause");return 0;

28.06.2016

Page 7: Основы С++ (массивы, указатели). Задачи с массивами

Основные задачи обработки массивов

• Заполнение и считывание в определённом порядке

• Упорядочение элементов по их значениям

• Сортировка на месте (в том же массиве)

• Создание оглавления (индексный массив)

• Алгоритмы переупорядочивания по оглавлению

• Информационный поиск

• Линейный поиск по совпадению

• Бинарный поиск по совпадению или по близости

• Поиск экстремумов

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ728.06.2016

Page 8: Основы С++ (массивы, указатели). Задачи с массивами

Случайные числа в C++

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ8

Сделаем работу с массивами удобнее. Будем заполнять их случайными числами

// получение случайного числа из диапазона от A до Bint A = 10, B = 11;cout << "Random value " << A + rand() % (B - A + 1) << "\n";// заполним массивfor (int i = 0; i < 10; i++) {arr[i] = rand() % 100; // значение от 0 до 99cout << arr[i] << " ";

}

Array_Snippets_02

Массив будет заполнен, но при перезапуске программы числа

изменяться не будут

// инициируем рандомизацию чиселsrand(time(0));

28.06.2016

Page 9: Основы С++ (массивы, указатели). Задачи с массивами

Заполнение массива случайными числами

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ9

#include <iostream>#include <ctime>using namespace std;int main() {int arr[10]; // определён массив из 10 элементов// инициируем рандомизацию чиселsrand(time(0));cout << "RAND_MAX = "<< RAND_MAX << "\n"; // значение константы RAND_MAX// получение случайного числа из диапазона от A до Bint A = 10, B = 11;cout << "Random value " << A + rand() % (B - A + 1) << "\n";// случайное вещественное значение (0, 1)cout << "Random double " << (double)rand() / RAND_MAX << "\n";// заполним массивfor (int i = 0; i < 10; i++) {arr[i] = rand() % 100; // значение от 0 до 99cout << arr[i] << " ";

}return 0;

}

Генератор случайных чисел rand() в С++(http://cppstudio.com/post/339/)

Новые генераторы случайных чисел(ГСЧ) из С++11 (http://www.quizful.net/post/random-number-generation-in-cpp11)

28.06.2016

Page 10: Основы С++ (массивы, указатели). Задачи с массивами

Указатели

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ10

тип *имя_указателя int *ptr1;double *ptr2;

Операция

разыменовывания

тип *имя_указателя = инициализирующее_выражение;тип *имя_указателя (инициализирующее_выражение);

Описание переменной с типом указателя

Формы записи инициализатора

double x = 3;int *ptr1(nullptr);double *ptr2;ptr2 = &x; // указатель связан с адресом x

28.06.2016

Page 11: Основы С++ (массивы, указатели). Задачи с массивами

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ11

double x = 3;int *ptr1(nullptr);double *ptr2;*ptr2 = 44; // Не компилируется. Почему?cout << *ptr2;

double x = 3;int *ptr1(nullptr);double *ptr2;*ptr1 = 44; // Так компилируется, но тоже не работает

double x = 3;int *ptr1(nullptr);double *ptr2;ptr2 = &x; // указатель связан с адресом xcout << *ptr2; // получение значение по адресу

28.06.2016

Page 12: Основы С++ (массивы, указатели). Задачи с массивами

Операции над указателями. Арифметика указателей

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ12

int x;int *ptr = &x;cout << ptr << " " << ptr++ << "\n";cout << ptr - 2 << "\n";cout << ptr + sizeof(int) * 4 << "\n";

0076FDD8 0076FDD40076FDD00076FE18

• операция разыменования (*)

• приведение типов

• присваивание

• получение адреса (&)

• аддитивные операции

• инкремент/декремент

• операции сравнения

28.06.2016

Page 13: Основы С++ (массивы, указатели). Задачи с массивами

Массивы и указатели

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ13

for (int i = 0;i < 10;i++) {arr[i] = i;cout << arr[i] << " ";

}cout << "\nExperiments!!!\n";for (int i = 0;i < 10;i++) {

*(arr + i) = 9 - i;cout << arr[i] << " ";

}

0 1 2 3 4 5 6 7 8 9

Experiments!!!

9 8 7 6 5 4 3 2 1 0

char *str = "ABCDEFGH";int i = 0;while (*(str + i)) { // <=> *(x+i)!='\0'

cout << str[i++] << "\n";}

Строки – это массивы символов

char *str = "ABCDEFGH";int i = 0;cout << ++str;

char *str = "ABCDEFGH";cout << strlen(str);

28.06.2016

Page 14: Основы С++ (массивы, указатели). Задачи с массивами

Почувствуйте разницу

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ14

10 14 -8 23 0 1 43 7 89

int arr[10]; // определён массив из 10 элементов// заполним массив

*(arr++)

arr[1]

arr смещён (содержит новый адрес) на (размер int) байт

и разыменован

К адресу начала массива arr прибавляется 1 * (размер int), затем к

адресу начала массива arr прибавляется 2 * (размер int)

arr++arr arr++

arr *(arr+1) *(arr+2)

arr[2]

28.06.2016

Page 15: Основы С++ (массивы, указатели). Задачи с массивами

Перебор элементов массива в обратном порядке

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ15

srand(time(0));int arr[10];for (int i = 0; i < 10; i++) {arr[i] = rand() % 100;cout << arr[i] << " ";

}// используем курсорint* curr = arr + 9;cout << endl;for (int i = 0; i < 10; i++)cout << *curr-- << " ";

C++ pointer arithmetic[http://www.tutorialspoint.com/cplusplus/cpp_pointer_arithmatic.htm]

ArrayPointers_01

Pointers and arrays[http://www.learncpp.com/cpp-tutorial/6-8-pointers-and-arrays/]

28.06.2016

Page 16: Основы С++ (массивы, указатели). Задачи с массивами

Алгоритмы работы с массивамиПоиск

Сортировки

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ1628.06.2016

Page 17: Основы С++ (массивы, указатели). Задачи с массивами

Сортировки

• Сортировка [sorting] –упорядочение набора некоторых объектов по некоторому критерию

• Обычно критерий является формализаций отношения на ключах элементов

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

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ17

Sedgewick, Wayne. Algorithms, 4-th ed.

28.06.2016

Page 18: Основы С++ (массивы, указатели). Задачи с массивами

Сортировка вставками: шаг 1

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ18

10 7 -34 0 18 -2 23

0 1 2 3 4 5 6

10 10 -34 0 18 -2 23

0 1 2 3 4 5 6

Сдвиг вправо

7 10 -34 0 18 -2 23

0 1 2 3 4 5 6

Размещение

28.06.2016

Page 19: Основы С++ (массивы, указатели). Задачи с массивами

Сортировка вставками: шаг 2

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ19

7 10 -34 0 18 -2 23

0 1 2 3 4 5 6

7 7 10 0 18 -2 23

0 1 2 3 4 5 6

Сдвиг вправо

-34 7 10 0 18 -2 23

0 1 2 3 4 5 6

Размещение

28.06.2016

Page 20: Основы С++ (массивы, указатели). Задачи с массивами

Сортировка вставками: шаг 3

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ20

-34 7 10 0 18 -2 23

0 1 2 3 4 5 6

Выбор элемента

-34 7 7 10 18 -2 23

0 1 2 3 4 5 6

Сдвиг вправо

-34 0 7 10 18 -2 23

0 1 2 3 4 5 6

Размещение

И так далее…

28.06.2016

Page 21: Основы С++ (массивы, указатели). Задачи с массивами

Сортировка вставками: реализация

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ21

void insertionSort(int a[], int n) {for (int i = 1; i < n; i++) {// Левее i-ого элемента массив отсортированint k = a[i]; // Запоминаем, потому что затрем сдвигомint j = i - 1;while (j >= 0 && a[j] > k) {

// Двигаем все элементы, больше ka[j + 1] = a[j];j--;

}a[j + 1] = k; // Ставим k на место

}}

Модифицировать сортировку. Минимальный элемент массива

предварительно установить на первую (с нулевым индексом) позицию. Как

изменится код? Реализуйте модификацию на семинарах.

28.06.2016

Page 22: Основы С++ (массивы, указатели). Задачи с массивами

Оглавление и его использование

• Оглавление (индексный массив) [index array] – массив курсоров, то есть индексов элементов некоторой последовательности

• Отметим, что часто (например, в теории баз данных) оглавлениеназывают «индексом», что приводит ещё к одной терминологической путанице

• Использование оглавления основано на косвенной адресации исходных данных:

• Вместо 𝐴[𝑖] пишем 𝐴[𝑹𝒆𝑴𝒂𝒑[𝒊]], где 𝑅𝑒𝑀𝑎𝑝[𝑖] – индекс элемента, который должен стоять на месте 𝑖 в соответствии с оглавлением 𝑅𝑒𝑀𝑎𝑝

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ2228.06.2016

Page 23: Основы С++ (массивы, указатели). Задачи с массивами

Напоминание: Индексные массивы

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ23

10 7 -34 0 18 -2 23

0 1 2 3 4 5 6

2 5 3 1 0 4 6

0 1 2 3 4 5 6

Исходный

массив A

Массив индексов (B)

для хранения

сортированного

представления

Как получить значение элемента в массиве А по элементу из массива B?

28.06.2016

Page 24: Основы С++ (массивы, указатели). Задачи с массивами

Пример: переупорядочение по оглавлению за линейное времяvoid ReMapSource(double* arrSource, int* arrReMap, int Len) {

// AReMapArr – массив курсоров, он будет испорчен…

int i, OldPlace, NewPlace;

double TmpElem;

for (int i = 0; i < Len-1; i++) {

NewPlace = arrReMap[i];

if (NewPlace == i) continue; // Если попалась неподвижная точка

OldPlace = i;

TmpElem = arrSource[i]; //Двигаем цикл перестановки:

do {

arrSource[OldPlace] = arrSource[NewPlace];

OldPlace = NewPlace;

NewPlace = arrReMap[OldPlace];

arrReMap[OldPlace] = OldPlace; //Фиксируем факт перемещения

} while (NewPlace != i);

arrSource[OldPlace] = TmpElem; //Завершаем двигать цикл

};

};© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ24

Здесь полезна трассировка, сделаем её на семинарах

28.06.2016

Page 25: Основы С++ (массивы, указатели). Задачи с массивами

Пример: бинарный поиск по совпадениюint binarySearch(int* arr, int arrLen, int seekingValue) {

int index = -1; // индекс найденного элемента

for (int i = 0, j = arrLen - 1, k = j % 2; i <= j;

k = (i + j) / 2) {

if (arr[k] == seekingValue) {

index = k; break; // нашли - прерываем цикл

} else {

if (seekingValue > arr[k]) i = k + 1;

else j = k - 1;

}

}

return index;

}

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ2528.06.2016

Page 26: Основы С++ (массивы, указатели). Задачи с массивами

Массивы и функции

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ26

#include <iostream>using namespace std;void changeArray(int[]);int main() {

int ar[] = { 1,2,3,4 };cout << *ar << *ar + 1 << *ar + 2 << *ar + 3;cout << "\n";changeArray(ar);cout << ar[0] << ar[1] << ar[2] << ar[3];cout << "\n";cout << *ar << *ar + 1 << *ar + 2 << *ar + 3;return 0;

}void changeArray(int ar[]) {

ar[0] = ar[3];}

Передача массива в функцию и немного подозрительного кода

28.06.2016

Page 27: Основы С++ (массивы, указатели). Задачи с массивами

Модификация с указателем

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ27

#include <iostream>using namespace std;void changeArray(int*);int main() {

int ar[] = { 1,2,3,4 };cout << *ar << *(ar + 1) << *(ar + 2) << *(ar + 3);cout << "\n";changeArray(ar);cout << *ar << *(ar + 1) << *(ar + 2) << *(ar + 3);return 0;

}void changeArray(int* ar) {

ar[0] = ar[3];}

28.06.2016

Page 28: Основы С++ (массивы, указатели). Задачи с массивами

Многомерные массивы

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ28

тип имя_массива[К1][K2]...[KN];

массив, элементами которого служат массивы

#include <iostream>using namespace std;

const int N = 3;const int M = 5;const int K = 7;int main() {

int multiArr[N][M][K]; // трёхмерный массивreturn 0;}

К всему прочему, мы можем описать массив указателей

28.06.2016

Page 29: Основы С++ (массивы, указатели). Задачи с массивами

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ29

#include <iostream>using namespace std;

const int N = 3;const int M = 5;const int K = 7;int main() {

int multiArr[N][M][K] = {1, 2, 3, 4, 5, 6, 7, 8};for (int i = 0; i < N; i++)

for (int j = 0; j < M; j++)for (int k = 0; k < K; k++)

cout << multiArr[i][j][k] << " ";return 0;

}

int multiArr[N][M][K] = { {1,2,3},{4,5},{6,7,8} };

Что изменится?

28.06.2016

Page 30: Основы С++ (массивы, указатели). Задачи с массивами

Многомерные массивы и указатели

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ30

const int N = 2;const int M = 2;const int K = 2;

int multiArr[N][M][K] = { {1,2},{3,4},{5,6}};

int multiArr[N][M][K] = { {1,2},{3,4} };

#include <iostream>using namespace std;

const int N = 2;const int M = 2;

int main() {int multiArr[N][M] = { {1,2},{3,4} };cout << *multiArr << "\n";cout << **multiArr << "\n";return 0;

}

*(*(multiArr + 1)) + 1 **multiArr + 1

28.06.2016

Page 31: Основы С++ (массивы, указатели). Задачи с массивами

Многомерные массивы с C++: проблемы

• Очень серьёзная проблема! В данном случае гибкость языка с кучей «синтаксического сахара» очень мешает школьникам…

• Многие источники, даже ориентированные на обучение, дают очень странные советы (называется – «Плодим уродцев»)

• Например: Two Dimensional Array (http://www.cppforschool.com/tutorial/array2.html)

1. void print(int A[][3], int N, int M) {

2. for (R = 0; R < N; R++)

3. for (C = 0; C < M; C++)

4. cout << A[R][C];

5. }

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ31

Константа!!! А без неё не получалось…

Кто ответит –

почему?

28.06.2016

Page 32: Основы С++ (массивы, указатели). Задачи с массивами

Многомерные массивы в С++: решения

• Выхода всего два:

1. Массив указателей на массивы

2. Класс-обёртка для одномерного массива:

• При этом создание класса может сделать работу с ним практически неотличимой от «обычного» массива

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ3228.06.2016

Page 33: Основы С++ (массивы, указатели). Задачи с массивами

Пример: динамический двумерный массив в С++11

• const auto RowCount = 2;

• const auto ColCount = 3;

• auto array = new double[RowCount][ColCount]; // Выделяем память

• // Заполняем массив

• for (int r = 0; r < RowCount; r++) {

• for (int c = 0; c < ColCount; c++) {

• array[r][c] = (r + 1)*(c + 1);

• };

• };

• // Распечатываем массив

• for (int r = 0; r < RowCount; r++) {

• for (int c = 0; c < ColCount; c++) {

• cout << array[r][c] << " ";

• };

• cout << endl;

• }

• cout << endl;

• delete[] array; // Удаляем массив

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ33

А вот и часть ответа

на предыдущий вопрос

28.06.2016

Page 34: Основы С++ (массивы, указатели). Задачи с массивами

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

1. template <typename T>

2. class MyMatrix {

3. size_t _rows;

4. size_t _columns;

5. std::unique_ptr<T[]> data; // Данные как одномерный массив

6. public:

7. MyMatrix(size_t rows, size_t columns)

8. : _rows{ rows }, _columns{ columns }, data{ nullptr } {

9. data = std::make_unique<T[]>(rows * columns);

10. } // Конструктор

11. size_t rows() const {return _rows;} // Число строк

12. size_t columns() const {return _columns;} // Число столбцов

13. T * operator[](size_t row) {

14. return row * _columns + data.get();

15. } // Индексатор

16. };

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ3428.06.2016

Page 35: Основы С++ (массивы, указатели). Задачи с массивами

Обсуждение примеров с двумерными массивами

• Класс из предыдущего примера можно использовать для замены обычного двумерного массива, только теперь можно делать размеры не константами!

• Было:

1. const auto RowCount = 2;

2. const auto ColCount = 3;

3. auto array = new double[RowCount][ColCount];

• Стало:

1. int RowCount = 3;

2. int ColCount = 4;

3. MyMatrix<double> MM(RowCount, ColCount);

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ3528.06.2016

Page 36: Основы С++ (массивы, указатели). Задачи с массивами

Решаем задачи. Массивы

1. В целочисленном массиве А определить и вывести на экран «расстояние» между первым вхождением минимального и первым вхождением максимального элементов. Расстояние между элементами A[i] и A[j] – количество элементов между ними.

2. По массиву целочисленному массиву A сформировать вещественный массив B, содержащий абсолютные значения отклонений элементов массива A от среднего значения элементов массива.

3. Выполнить некольцевой сдвиг всех элементов массива на K позиций вправо.

4. Из целочисленного массива удалить все отрицательные элементы со сдвигом влево.

5. Выполнить кольцевой сдвиг элементов вещественного массива на Kпозиций влево.

6. По целочисленному массиву A сформировать индексный массив B для хранения сортированного представления массива A.

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ3628.06.2016

Page 37: Основы С++ (массивы, указатели). Задачи с массивами

© Максименкова О.В., Незнанов А.А., ДПИ и ДАДиИИ

ФКН НИУ ВШЭ37

Спасибо за внимание!

Максименкова Ольга Вениаминовна

Старший преподаватель Департамента программной инженерии, ФКН

E-mail: [email protected]

Blog: Stop To Scale (http://stoptoscale.blogspot.ru)

28.06.2016