1 / 44

Д.з.

Д.з. Задача 3*: последняя ненулевая цифра n!. Вариант 1: (не совсем правильный) p = 1; for (int i = 1; i <= n; i++) { p *= i; … убрать нули на конце … } … переполнение для больших p  …

Télécharger la présentation

Д.з.

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Д.з.

  2. Задача 3*: последняя ненулевая цифра n! Вариант 1: (не совсем правильный) p = 1; for (int i = 1; i <= n; i++) { p *= i; … убрать нули на конце … } … переполнение для больших p … Вариант 2: (не совсем правильный)Оставлять от p только последнюю цифруНельзя.. 24! = 620448401733239439360000 25! = 15511210043330985984000000 Вариант 3: Оставлять от p несколько последних цифр - работает 6*5 != 4

  3. Задача 3*: схема алгоритма Теперь нас интересует последняя цифра – она точно не нулевая Вариант 4: p = 1; for (int i = 1; i <= n; i++) { … выкинуть из i все сомножители 2 и 5… p *= i; p %= 10; } … умножить на 2 нужное количество раз… 3

  4. int num2 = 0; // Количество двоек int num5 = 0; // Количество пятерок int p = 1; // Последняя цифра произведения for (int i = 2; i <= n; i++) { int i1 = i; while (i1 % 2 == 0) {// Выбрасываем из i все сомножители 2 i1 /= 2; num2++; } while (i1 % 5 == 0) {// Выбрасываем из i все сомножители 5 i1 /= 5; num5++; } p *= i1; p %= 10; } // Добавляем несократившиеся двойки for (int j = 0; j < num2 - num5; j++) { p *= 2; p %= 10; } 4

  5. См также http://oeis.org/A008904 (спасибо за ссылку Дмитрию Гинзбургу)

  6. void reverse(int* a, int n) { int* p = a; int *q = a+n-1; for (; p < q; p++, q--) { int tmp = *p; *p = *q; *q = tmp; } } // Пример вызова int b[100]; … заполнение b … reverse(b, 100); Без указателей void reverse(int* a, int n) { for (int i = 0, j = n-1; i < j; i++, j--) { int tmp = a[i]; a[i] = a[j]; a[j] = tmp; } } Mожно использоватьстандартный swap: swap(*p, *q);swap(a[i], a[j]); Задача 1: reverse

  7. void reverse(int* b, int* e) { for (int *p = b, *q = e; p < q;p++, q--) { swap(*p, *q); } } // Пример вызова int b[100]; … заполнение b … reverse(b, b+99); Задача 1: reverse – другой вариант интeрфейса

  8. Кстати: auto • auto auto переменная = начальное значение; auto x = sin(1); // x будет double void reverse(int* b, int* e) { for (auto p = b, q= e; p < q;p++, q--) { auto tmp = *p; *p = *q; *q = tmp; } } определять тип переменной автоматически, по типу выражения

  9. Задача 2: треугольный массив Это, может быть, и не самый оптимальный вариант, но не мог удержаться:) int* a[10]; // Создаем.. for (int i = 0; i<10; i++) { a[i] = new int[i+1]; } // Заполняем for (int i = 0; i<10; i++) { for (int j = 0; j<=i; j++) { a[i][j] = (i == j); } } // Печатаем for (int i = 0; i<10; i++) { for (int j = 0; j<=i; j++) { cout << a[i][j] << " "; } cout << "\n"; } 9

  10. Задача 3: order Тут удобно воспользоваться перегрузкой имен и назвать эту функцию тоже order. // Вспомогательная функция: // Упорядочиваем два числа void order(int& x, int& y) { if (x > y) { int tmp = x; x = y; y = tmp; } } void order(int& x, int& y, int& z) { order(x, y); order(x, z); order(y, z); } // Пример вызова: int a = 3, b = 1, c = 2; order(a, b, c); cout << a << b << c; 10

  11. Обычно параметры, которыехотят изменить, передают по ссылке void dbl(int& i) { i *= 2; } int m = 10; dbl(m); А можно передать указатель на переменную(так пишут на С) void dbl(int* p) {*p *= 2; } int m = 10; dbl(&m); Задача 4: Передача параметров по указателю(старинный способ изменения параметров:) Теперь m = 10

  12. Разные замечания 12

  13. Как можно (очень примерно) представлять себе, что такое ссылка Ссылка – это (очень примерно) то же, что указатель • который устанавливается один раз при создании • к которому * добавляется автоматически. Ну например: int& x = a[5]; x = 77; cout << x; примерно то же, что int* x = &a[5]; *x = 77; cout << *x;

  14. Что может означать, если параметр функции – указатель? void f(abc *p); // Что может передаваться такой функции? • abc* p = new abc; // Динамическая памятьf(p); • abc a[100]; // Массивf(a); • abc x; // Адрес переменнойf(&x); // (передача параметра по указателю, // вместо использования ссылок. // Обычно встречается в программах на С) чаще всего

  15. typedef 15

  16. typedef Ошибка: у обеих функций одинаковые параметры то же, что int* a[10]; Синтаксис: typedef описание переменной; typedef unsigned long ulong; typedef int* my_array[10]; my_array a; Замечание:typedef не определяет новый тип – это просто сокращенная запись для существующего типа void f(unsigned long i) { … } void f(ulong j) { … } 16

  17. Зачем нужен typedef ? примерно то, что называют инкапсуляция Сокращенная записьtypedef unsigned long ulong; typedef int MY_INTEGER; Если мы планируем потом менять тип Технические причины – определение сложных типов: typedef int* pint; pint a[10];p = new pint[20]; 17

  18. Классы 18

  19. Пример поля список инициализации конструктор методы пример создания объекта пример вызова метода class time { int hour; int min; public: time(int h = 0, int m = 0); void print(); void inc(); }; void time::print() { cout << hour << ":" << min; } time::time(int h, int min) : hour(h), min(m) {} void time::inc() { min++; if ( min == 60 ) { min = 0; hour++; } } time t(9, 30); t.print(); t.inc(); 19

  20. Конструктор Конструктор – особый метод, который всегда вызывается первым, при создании обьекта. • Имя совпадает с именем класса • Может быть много параметров • Довольно часто бывает перегруженили имеет параметры по умолчанию time(int h, int min) : hour(h), min(m) {}

  21. Вызов конструктора • Неявно при описании переменной time t(9, 30); • Неявно при динамическом создании с помощью new time* p = new time(9, 30); • (Относительно редко) Временные объекты f(time(9, 30)); • Если 1 параметр, можно написать так: time t = 11; (то же, что time t(11); ) будет существовать временно, пока выполняется оператор

  22. Списки инициализации • Часто в констукторе пишут так: time::time(int h, int m) {hour = h; min = m;} • Ошибка! Лучше немного иначе: time::time(int h, int m) : hour(h), min(m){} конструктор(…) :поле(нач.значение),поле(нач.значение), …{ …} Почему лучше? • так быстрее • иногда только так и можно • сразу видно, что вы знаете С++ :) список инициализации 22

  23. Деструктор ~имя класса() class abc { … ~abc() { cout << "Пока!"; } }; Задаем какие-то действия при уничтожении объекта 23

  24. public и private • Могут чередоваться • public – можно использовать везде • private – можно использовать только внутри класса Слово: инкапсуляция (information hiding) • Поля обычно private – зачем? • Легче менять • Можно контролировать корректность данных class abc { int i; void f(); public: doublexyz; int g(); private: int fld; int ff(); … }; abc x; x.fld; ошибка - обращение к private полю 24

  25. Еще технические детали • p->abcто же, что (*p).abc Например: p->print(); p->hour; • this – указатель на текущий объект.Mожет использоваться только в методах Например:hour это в методе то же, чтоthis->hour • функции, описанные прямо в классе class abc {void f() { …какой-то код…} • В чем разница structи class? Почти одно и то же. Разница только в том, public или private сначала: • class abc {void f() • struct abc { void f() inline функция private public

  26. Конструктор по умолчанию time t;time* p = new time; Конструктор по умолчанию (default constructor) - конструктор, у которого нет параметров • (или м.б. есть, но для всех задано значение по умолчанию) class time { time(int h = 0, int m = 0); • В частности, вызывается, если создается массив time a[100]; • Если к-ра по умолчанию нет, то будет ошибка какой вызывается конструктор? тоже конструктор по умолчанию

  27. Технические детали: конструкторы по умолчанию создается автоматически Создается автоматически, если вообще нет конструкторов class abc { … нет ни одного конструктора …}; Автоматически добавляется: abc (){} 28

  28. Объявление класса class abc; class klm { abc* p; … }; class abc { klm* q; … }; что-то вроде прототипа, но для классов используем класс до того, как он описан 29

  29. Типичная ошибка class abc { int a, b; } void main() { … Пропущена ; в конце класса! (Сообщение об ошибке, как правило, непонятное). 30

  30. Константы 31

  31. Как определять целые константы? • const int n = 100; Можно использовать в массивах, switch и т.д.int a[n]; 32

  32. enum a=0, b=1, c=2, d=3 a=0, b=1, c=10,d=11,e=12 do  do_ ! enum {a, b, c, d}; enum {a,b,c=10,d,e}; можно задавать имя: enum scale {do, re, mi, fa, sol, la, si}; Тогда получится новый тип, его можно использовать при перегрузке и т.д. 33

  33. Константные объекты • const double pi = 3.1415926;const time lunch_time(12, 50);constint a[9] = {7, 9, 11, 13, 15, 19, 22, 28, 48}; Мы обещаем не менять объект Какой смысл? • Компилятор нас проверит (не даст нам менять) • Если мы очень захотим, мы сможем обойти • Иногда компилятор будет запрещать что-то сделать потому что это может привести к изменению const • Компилятор может что-то оптимизировать • Может быть, разместит в особой памяти • Может быть, подставит при компиляции значениеi += a[2];  i += 11; • сonst - полезная информация при чтении программы 34

  34. Насчет мороженного за 28 копеек

  35. Константы и указатели Ошибка, *p нельзя менять OK, *p можно менять Ошибка, p нельзя переставлять const int* p; Обещаем не менять место, на которое указывает указатель *p = 5; int* const p; Обещаем не переставлять указатель на другое место *p = 5; p = &i; const int* const p; Обещаем ничего не менять.. 36

  36. Константы и указатели в параметрах функций Ошибка, *p нельзя менять Мы точно знаем, что тут a не изменился. Это удобно… void myfunc(constint* p) { *p = 5; • Обещаем не менять *p внутри функции. Зачем? • Ловим ошибки в программе • Интерфейс функции становится понятнее (легче тем, кто будет использовать) int a[100];myfunc(a); 37

  37. Все тоже относитсяи к ссылкам в параметрах. void f(const abc& x) { … } Обещаем не менять x внутри функции Кстати, зачем вообще const abc& а не abc x? Более эффективно для большихabc Если abc – это базовый класс для иерархии классов(обсудим позже…) Константы и ссылки в параметрах функций 38

  38. Немного о строках 39

  39. Строки ('старое' представление данных, в стиле С) char s[100]; cin >> s; // Ввести до пробела cin.getline(s, 100);// Ввести всю строку Строчки – это просто массивы символов. Конец строки обозначается символом '\0'. Т.е., например, если вы выполнили cin >> s; и ввели строчку "abc", то у вас будет: s[0] == 'a', s[1] == 'b', s[2] == 'c', s[3] == '\0‘; (а в остальных элементах массива s будет неизвестно что). 40

  40. Задачи

  41. Задачи 1 Описать класс «стек целых чисел». Известно, что в стеке точно не больше 100 чисел. Достаточно определить только конструктор, push и pop.Пример использования:stack s;s.push(3);s.push(5);cout << s.pop(); • То же, что задача 1, но количество элементов не ограничено (т.е. память при необходимости должна отводиться динамически). (Я предложил бы использовать массив, который отводится динамически, а потом при необходимости отводится новый, побольше. Но вы можете реализовать и любой другой способ, их много..) Для тех, кто сделает задачу 2, задачу 1 делать не надо, она засчитается автоматически. Задачи 3 и 4 на следующих слайдах. 42

  42. Задачи 2 Описать для стека метод top() - возвращает последний эл-т как lvalue. Например:s.top() = 5; // Заменить// верхний эл-т стекаs.top()++; // Увеличить// верхний эл-т стека • Описать функцию для сравнения двух строк.Пример вызова: char s1[100]; char s2[100]; cin.getline(s1, 100); cin.getline(s2, 100); bool b = compare(s1, s2); // true, если строки равны • Не забывайте о constв параметрах • Не забывайте, что сравнивать надо только до '\0'. Дальше в строке может идти все что угодно, и это сравнивать не надо. 43

  43. Задачи 3 * (Немного на сообразительность):Определить для стека функцию класса int product(), которая возвращает произведение всех чисел не стеке. При этом эта функция должна работать быстро даже для очень большого стека. Замечания: • Можно придумать реализацию, при которой время вообще не зависит от размера, оно всегда одинаково. • Написать функцию было бы очень просто, если бы на стеке не могло бы быть нулей. • С нулями все немного сложнее, м.б. придется хранить какие-то дополнительные данные. • Обратите внимание, пожалуйста, задачи 3 и 5 не должны правильно работать вместе. Т.е. достаточно, чтобы решение задачи 5 обрабатывало только push и pop, обработка top не обязательна. 44

More Related