SlideShare une entreprise Scribd logo
1  sur  54
Télécharger pour lire hors ligne
Лекция 2.
ЭЛЕМЕНТАРНЫЕ
СТРУКТУРЫ ДАННЫХ.
Мацкевич С. Е.
План лекции 2
§  Структура данных «Динамический массив».
Амортизированное время добавления элемента.
§  Однонаправленные, двунаправленные списки.
§  Поиск, добавление элементов, слияние списков.
§  Абстрактные типы данных «Стек», «Очередь», «Дек».
Способы реализации.
§  Структура данных «Двоичная куча».
§  Абстрактный тип данных «Очередь с приоритетом».
2
Абстрактные типы данных и структуры
данных
Определение. Абстрактный тип данных (АТД) – это тип
данных, который предоставляет для работы с элементами
этого типа определённый набор функций, а также
возможность создавать элементы этого типа при помощи
специальных функций.

Вся внутренняя структура такого типа спрятана – в этом
и заключается суть абстракции.
3
Абстрактные типы данных и структуры
данных
Напоминание. Структура данных – программная
единица, позволяющая хранить и обрабатывать
множество однотипных и/или логически
связанных данных.

Абстрактный тип данных определяет набор функций,
независимых от конкретной реализации типа, для
оперирования его значениями. Конкретные реализации
АТД будем также называть структурами данных.
4
СД «Массив»
Напоминание. Массив – набор однотипных компонентов
(элементов), расположенных в памяти непосредственно
друг за другом, доступ к которым осуществляется
по индексу (индексам).
Традиционно индексирование элементов массива
начинают с 0.
5
20
 34
 11
 563
 23
 -1
 2
 0
 -33
 7
0
 1
 2
 3
 4
 5
 6
 7
 8
 9
СД «Массив»
6
//	
  Создание	
  массивов	
  в	
  C++:	
  
	
  
//	
  Массив	
  из	
  10	
  целых	
  чисел.	
  Создается	
  на	
  стеке	
  потока.	
  
int	
  intArray1[10];	
  
	
  
//	
  Массив	
  из	
  заранее	
  неизвестного	
  количества	
  целых	
  чисел.	
  
//	
  Создается	
  в	
  куче	
  процесса.	
  
//	
  Такие	
  массивы	
  называют	
  массивами	
  переменной	
  длины.	
  
int	
  n	
  =	
  0;	
  
cin	
  >>	
  n;	
  
int*	
  intArray2	
  =	
  new	
  int[n];	
  
delete[]	
  intArray2;
СД «Динамический массив»
Определение. СД «Динамический массив» – структура
данных с операциями
§  Добавление элемента в конец массива «Add»
(или PushBack),
§  Доступ к элементу массива по индексу за 𝑂(1)
«GetAt» (или оператор []).
7
СД «Динамический массив»
Динамический массив содержит внутренний массив
фиксированной длины для хранения элементов.
Внутренний массив называется буфером.
Помнит текущее количество добавленных элементов.
Размер буфера имеет некоторый запас для возможности
добавления новых элементов.
Пример. Буфер размера 14 заполнен 10 элементами.
8
Т
 е
 х
 н
 о
 п
 а
 р
 к
 !
0
 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
СД «Динамический массив»
Буфер может закончиться…
Если буфер закончился, то
при добавлении нового элемента:
§  выделим новый буфер,
больший исходного;
§  скопируем содержимое старого буфера в новый;
§  добавим новый элемент.
9
Т
 е
 х
 н
 о
 п
 а
0
 1
 2
 3
 4
 5
 6
Т
 е
 х
 н
 о
 п
 а
 р
0
 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
СД «Динамический массив»
10
//	
  Структура,	
  описывающая	
  массив	
  чисел	
  с	
  плавающей	
  точкой.	
  
struct	
  CArray1	
  {	
  
	
  	
  	
  	
  double*	
  Buffer;	
  
	
  	
  	
  	
  int	
  BufferSize;	
  
	
  	
  	
  	
  int	
  RealSize;	
  
	
  
	
  	
  	
  	
  CArray()	
  :	
  Buffer(	
  0	
  ),	
  BufferSize(	
  0	
  ),	
  RealSize(	
  0	
  )	
  {}	
  
};	
  
	
  
//	
  Доступ	
  к	
  элементу	
  массива	
  по	
  индексу.	
  
double	
  GetAt(	
  const	
  CArray1&	
  arr,	
  int	
  index	
  )	
  
{	
  
	
  	
  	
  	
  assert(	
  index	
  >=	
  0	
  &&	
  index	
  <	
  arr.RealSize	
  &&	
  arr.Buffer	
  !=	
  0	
  );	
  
	
  	
  	
  	
  return	
  arr.Buffer[index];	
  
}	
  
СД «Динамический массив»
11
//	
  Увеличение	
  буфера.	
  
void	
  grow(	
  CArray1&	
  arr	
  )	
  
{	
  
	
  	
  	
  	
  //	
  Создаем	
  новый	
  буфер.	
  
	
  	
  	
  	
  int	
  newBufferSize	
  =	
  arr.BufferSize	
  *	
  2;	
  
	
  	
  	
  	
  double*	
  newBuffer	
  =	
  new	
  double[newBufferSize];	
  
	
  	
  	
  	
  //	
  Копируем.	
  
	
  	
  	
  	
  for(	
  int	
  i	
  =	
  0;	
  i	
  <	
  arr.RealSize;	
  ++i	
  )	
  
	
  	
  	
  	
  	
  	
  	
  	
  newBuffer[i]	
  =	
  arr.Buffer[i];	
  
	
  	
  	
  	
  //	
  Чистим	
  старый	
  буфер.	
  
	
  	
  	
  	
  delete[]	
  arr.Buffer;	
  
	
  	
  	
  	
  arr.Buffer	
  =	
  newBuffer;	
  
	
  	
  	
  	
  arr.BufferSize	
  =	
  newBufferSize;	
  
}	
  
//	
  Добавление	
  нового	
  элемента.	
  
void	
  Add(	
  CArray1&	
  arr,	
  double	
  element	
  )	
  
{	
  
	
  	
  	
  	
  if(	
  arr.RealSize	
  ==	
  arr.BufferSize	
  )	
  
	
  	
  	
  	
  	
  	
  	
  	
  grow(	
  arr	
  );	
  
	
  	
  	
  	
  assert(	
  arr.RealSize	
  <	
  arr.BufferSize	
  &&	
  arr.Buffer	
  !=	
  0	
  );	
  
	
  	
  	
  	
  arr.Buffer[arr.RealSize++]	
  =	
  element;	
  
}	
  
СД «Динамический массив»
Как долго работает функция Add добавления элемента?
§  В лучшем случае = 𝑂(1)
§  В худшем случае = 𝑂(𝑛)
§  В среднем?
Имеет смысл рассматривать несколько операций
добавления и оценить среднее время в контексте
последовательности операций.
Подобный анализ называется амортизационным.
12
Амортизационный анализ
Определение (по Кормену…). При амортизационном
анализе время, требуемое для выполнения
последовательности операций над структурой данных,
усредняется по всем выполняемым операциям.
Этот анализ можно использовать, например, чтобы
показать, что даже если одна из операций
последовательности является дорогостоящей, то при
усреднении по всей последовательности средняя
стоимость операций будет небольшой.
13
Амортизационный анализ
Амортизационный анализ
отличается от анализа
средних величин тем, что в
нем не учитывается
вероятность.
При амортизационном
анализе гарантируется
средняя
производительность
операций в наихудшем
случае.

14
Амортизационный анализ
Определение. Пусть S(n) – время выполнения
последовательности всех n операций в наихудшем
случае. Амортизированной стоимостью (временем)
называется среднее время, приходящееся на одну
операцию ​ 𝑆(𝑛)⁄𝑛 .

Оценим амортизированную стоимость операций Add
динамического массива.
15
СД «Динамический массив»
Утверждение. Пусть в реализации функции grow() буфер
удваивается. Тогда амортизированная стоимость функции
Add составляет 𝑂(1).
Доказательство. Рассмотрим последовательность из n
операций Add.
Обозначим 𝑃(𝑘) - время выполнения Add в случае, когда
RealSize = k.
§  𝑃(𝑘)=​ 𝑐↓1 𝑘, если 𝑘=​2↑𝑚 .
§  𝑃(𝑘)=​ 𝑐↓2 , если 𝑘≠​2↑𝑚 .
𝑆(𝑛)=∑𝑘=1↑𝑛▒𝑃(𝑘) ≤​ 𝑐↓1 ∑𝑚:​2↑𝑚 < 𝑛↑▒​2↑𝑚  +​ 𝑐↓2 ∑𝑘: 𝑘≠​
2↑𝑚 ↑▒1 = 𝑂(𝑛).
Амортизированное время 𝑇(𝑛)=​ 𝑆(𝑛)⁄𝑛 =​ 𝑂(𝑛)⁄𝑛 = 𝑂(1).
16
СД «Динамический массив»
17
//	
  Класс	
  «Динамический	
  массив».	
  
class	
  CArray	
  {	
  
public:	
  
	
  	
  	
  	
  CArray()	
  :	
  buffer(	
  0	
  ),	
  bufferSize(	
  0	
  ),	
  realSize(	
  0	
  )	
  {}	
  
	
  	
  	
  	
  ~CArray()	
  {	
  delete[]	
  buffer;	
  }	
  
	
  
	
  	
  	
  	
  //	
  Доступ	
  по	
  индексу.	
  
	
  	
  	
  	
  double	
  GetAt(	
  int	
  index	
  )	
  const;	
  
	
  	
  	
  	
  double	
  operator[](	
  int	
  index	
  )	
  const	
  {	
  return	
  GetAt(	
  index	
  );	
  }	
  
	
  	
  	
  	
  double&	
  operator[](	
  int	
  index	
  );	
  
	
  
	
  	
  	
  	
  //	
  Добавление	
  нового	
  элемента.	
  
	
  	
  	
  	
  void	
  Add(	
  double	
  element	
  );	
  
	
  
private:	
  
	
  	
  	
  	
  double*	
  buffer;	
  //	
  Буфер.	
  
	
  	
  	
  	
  int	
  bufferSize;	
  //	
  Размер	
  буфера.	
  
	
  	
  	
  	
  int	
  realSize;	
  //	
  Количество	
  элементов	
  в	
  массиве.	
  
	
  
	
  	
  	
  	
  void	
  grow();	
  
};	
  
	
  
СД «Динамический массив»
18
//	
  Доступ	
  к	
  элементу.	
  
double	
  CArray::GetAt(	
  int	
  index	
  )	
  
{	
  
	
  	
  	
  	
  assert(	
  index	
  >=	
  0	
  &&	
  index	
  <	
  realSize	
  &&	
  buffer	
  !=	
  0	
  );	
  
	
  	
  	
  	
  return	
  buffer[index];	
  
}	
  
//	
  Увеличение	
  буфера.	
  
void	
  CArray::grow()	
  
{	
  
	
  	
  	
  	
  int	
  newBufferSize	
  =	
  bufferSize	
  *	
  2;	
  
	
  	
  	
  	
  double*	
  newBuffer	
  =	
  new	
  double[newBufferSize];	
  
	
  	
  	
  	
  for(	
  int	
  i	
  =	
  0;	
  i	
  <	
  realSize;	
  ++i	
  )	
  
	
  	
  	
  	
  	
  	
  	
  	
  newBuffer[i]	
  =	
  buffer[i];	
  
	
  	
  	
  	
  delete[]	
  buffer;	
  
	
  	
  	
  	
  buffer	
  =	
  newBuffer;	
  
	
  	
  	
  	
  bufferSize	
  =	
  newBufferSize;	
  
}	
  
//	
  Добавление	
  элемента.	
  
void	
  CArray::Add(	
  double	
  element	
  )	
  
{	
  
	
  	
  	
  	
  if(	
  realSize	
  ==	
  bufferSize	
  )	
  
	
  	
  	
  	
  	
  	
  	
  	
  grow(	
  arr	
  );	
  
	
  	
  	
  	
  assert(	
  realSize	
  <	
  bufferSize	
  &&	
  buffer	
  !=	
  0	
  );	
  
	
  	
  	
  	
  buffer[realSize++]	
  =	
  element;	
  
}	
  
Связные списки
Определение. Связный список -
динамическая структура данных, состоящая из узлов,
каждый из которых содержит как собственно данные,
так и одну или две ссылки («связки») на следующий и/
или предыдущий узел списка.
Преимущество перед массивом:
§  Порядок элементов списка может не совпадать с
порядком расположения элементов данных в памяти, а
порядок обхода списка всегда явно задаётся его
внутренними связями.
19
Связные списки
Односвязный список (однонаправленный связный
список)


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



Здесь ссылки в каждом узле указывают на предыдущий и на
последующий узел в списке.
По двусвязному списку можно передвигаться в любом
направлении – как к началу, так и к концу.
В этом списке проще производить удаление и перестановку
элементов, так как всегда известны адреса тех элементов
списка, указатели которых направлены на изменяемый
элемент.
21
Связные списки
Операции со списками:
§  Поиск элемента,
§  Вставка элемента,
§  Удаление элемента,
§  Объединение списков,
§  …
22
Связные списки
23
//	
  Элемент	
  двусвязного	
  списка	
  с	
  целочисленными	
  
//	
  значениями.	
  
struct	
  CNode	
  {	
  
	
  	
  	
  	
  int	
  Data;	
  
	
  	
  	
  	
  CNode*	
  Next;	
  
	
  	
  	
  	
  CNode*	
  Prev;	
  
	
  
	
  	
  	
  	
  CNode()	
  :	
  Data(	
  0	
  ),	
  Next(	
  0	
  ),	
  Prev(	
  0	
  )	
  {}	
  
};	
  
	
  
	
  
Связные списки
24
//	
  Линейный	
  поиск	
  элемента	
  «a»	
  в	
  списке.	
  
//	
  Возвращает	
  0,	
  если	
  элемент	
  не	
  найден.	
  
СNode*	
  Search(	
  CNode*	
  head,	
  int	
  a	
  )	
  
{	
  
	
  	
  	
  	
  CNode*	
  current	
  =	
  head;	
  
	
  	
  	
  	
  while(	
  current	
  !=	
  0	
  )	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  if(	
  current-­‐>Data	
  ==	
  a	
  )	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  current;	
  
	
  	
  	
  	
  	
  	
  	
  	
  current	
  =	
  current-­‐>Next;	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  return	
  0;	
  
}	
  
	
  
Время работы в худшем случае = O(n), где n – длина списка.
Связные списки
25
//	
  Вставка	
  элемента	
  «a»	
  после	
  текущего.	
  
СNode*	
  InsertAfter(	
  CNode*	
  node,	
  int	
  a	
  )	
  
{	
  
	
  	
  	
  	
  assert(	
  node	
  !=	
  0	
  );	
  
	
  	
  	
  	
  //	
  Создаем	
  новый	
  элемент.	
  
	
  	
  	
  	
  CNode*	
  newNode	
  =	
  new	
  CNode();	
  
	
  	
  	
  	
  newNode-­‐>Data	
  =	
  a;	
  
	
  	
  	
  	
  newNode-­‐>Next	
  =	
  node-­‐>Next;	
  
	
  	
  	
  	
  newNode-­‐>Prev	
  =	
  node;	
  
	
  	
  	
  	
  //	
  Обновляем	
  Prev	
  следующего	
  элемента,	
  если	
  он	
  есть.	
  
	
  	
  	
  	
  if(	
  node-­‐>Next	
  !=	
  0	
  )	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  node-­‐>Next-­‐>Prev	
  =	
  newNode;	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  //	
  Обновляем	
  Next	
  текущего	
  элемента.	
  
	
  	
  	
  	
  node-­‐>Next	
  =	
  newNode;	
  
	
  	
  	
  	
  return	
  newNode;	
  
}	
  
	
  
Время работы = O(1).
Связные списки
26
//	
  Удаление	
  элемента.	
  
void	
  DeleteAt(	
  CNode*	
  node	
  )	
  
{	
  
	
  	
  	
  	
  assert(	
  node	
  !=	
  0	
  );	
  
	
  	
  	
  	
  //	
  Обновляем	
  Prev	
  следующего	
  элемента,	
  если	
  он	
  есть.	
  
	
  	
  	
  	
  if(	
  node-­‐>Next	
  !=	
  0	
  )	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  node-­‐>Next-­‐>Prev	
  =	
  node-­‐>Prev;	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  //	
  Обновляем	
  Next	
  предыдущего	
  элемента,	
  если	
  он	
  есть.	
  
	
  	
  	
  	
  if(	
  node-­‐>Prev	
  !=	
  0	
  )	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  node-­‐>Prev-­‐>Next	
  =	
  node-­‐>Next;	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  delete	
  node;	
  
}	
  
	
  
Время работы = O(1).
Связные списки
27
//	
  Объединение	
  списков.	
  К	
  списку	
  1	
  подцепляем	
  список	
  2.	
  
void	
  Union(	
  CNode*	
  head1,	
  CNode*	
  head2	
  )	
  
{	
  
	
  	
  	
  	
  assert(	
  head1	
  !=	
  0	
  &&	
  head2	
  !=	
  0	
  );	
  
	
  	
  	
  	
  //	
  Идем	
  в	
  хвост	
  списка	
  1.	
  
	
  	
  	
  	
  CNode*	
  tail1	
  =	
  head1;	
  
	
  	
  	
  	
  for(	
  ;	
  tail1-­‐>Next	
  !=	
  0;	
  tail1	
  =	
  tail1-­‐>Next	
  );	
  
	
  	
  	
  	
  //	
  Обновляем	
  Next	
  хвоста.	
  
	
  	
  	
  	
  tail1-­‐>Next	
  =	
  head2;	
  
	
  	
  	
  	
  //	
  Обновляем	
  Prev	
  головы	
  второго	
  списка.	
  
	
  	
  	
  	
  head2-­‐>Prev	
  =	
  tail1;	
  
}	
  
	
  
Время работы = O(n), где n – длина первого списка.
Связные списки
Недостатки списков:
§  Сложность определения элемента по его номеру (индексу).
§  На поля указатели расходуется дополнительная память.
§  Элементы списка могут располагаться в памяти
разреженно, что оказывает негативный эффект на
кэширование процессора.
Преимущества списков перед массивом:
§  Быстрая вставка элемента в любом месте списка. В том
числе в начало и в конец, если имеются соответствующие
указатели.
§  Быстрое удаление любого элемента. В том числе в начало
и в конец, если имеются соответствующие указатели.
28
АТД «Стек»
Определение. Стек – абстрактный тип данных (или структура данных),
представляющий из себя список элементов, организованный по принципу
LIFO = Last In First Out, «последним пришел, первым вышел».
Операции:
1.  Вставка (Push)
2.  Извлечение (Pop) – извлечение элемента, добавленного последним.
29
СД «Стек»
Стек можно реализовать с помощью массива или с
помощью списка.
Реализация с помощью массива.



Храним указатель на массив и текущее количество
элементов в стеке.
Можно использовать динамический массив.
30
СД «Стек»
31
//	
  Стек	
  целых	
  чисел,	
  реализованный	
  с	
  помощью	
  массива.	
  
class	
  CStack	
  {	
  
public:	
  
	
  	
  	
  	
  CStack(	
  int	
  size	
  );	
  
	
  	
  	
  	
  ~CStack();	
  
	
  
	
  	
  	
  	
  //	
  Добавление	
  и	
  извлечение	
  элемента	
  из	
  стека.	
  
	
  	
  	
  	
  void	
  Push(	
  int	
  a	
  );	
  
	
  	
  	
  	
  int	
  Pop();	
  
	
  
	
  	
  	
  	
  //	
  Проверка	
  на	
  пустоту.	
  
	
  	
  	
  	
  bool	
  IsEmpty()	
  const	
  {	
  return	
  top	
  ==	
  -­‐1;	
  }	
  
	
  
private:	
  
	
  	
  	
  	
  int*	
  buffer;	
  
	
  	
  	
  	
  int	
  bufferSize;	
  
	
  	
  	
  	
  int	
  top;	
  
};	
  
СД «Стек»
32
//	
  В	
  конструкторе	
  создаем	
  буфер.	
  
CStack::CStack(	
  int	
  size	
  )	
  :	
  
	
  	
  	
  	
  bufferSize(	
  size	
  ),	
  
	
  	
  	
  	
  top(	
  -­‐1	
  )	
  
{	
  
	
  	
  	
  	
  buffer	
  =	
  new	
  int[bufferSize];	
  
}	
  
//	
  В	
  деструкторе	
  удаляем	
  буфер.	
  
CStack::~CStack()	
  
{	
  
	
  	
  	
  	
  delete[]	
  buffer;	
  
}	
  
	
  
//	
  Добавление	
  элемента.	
  
void	
  CStack::Push(	
  int	
  a	
  )	
  
{	
  
	
  	
  	
  	
  assert(	
  top	
  +	
  1	
  <	
  bufferSize	
  );	
  
	
  	
  	
  	
  buffer[++top]	
  =	
  a;	
  
}	
  
//	
  Извлечение	
  элемента.	
  
int	
  CStack::Pop()	
  
{	
  
	
  	
  	
  	
  assert(	
  top	
  !=	
  -­‐1	
  );	
  
	
  	
  	
  	
  return	
  buffer[top-­‐-­‐];	
  
}	
  
АТД «Очередь»
Определение. Очередь – абстрактный тип данных (или структура данных),
представляющий из себя список элементов, организованный по принципу
FIFO = First In First Out, «первым пришел, первым вышел».
Операции:
1.  Вставка (Enqueue)
2.  Извлечение (Dequeue) – извлечение элемента, добавленного первым.
33
СД «Очередь»
Очередь также как и стек можно реализовать с помощью массива
или с помощью списка.
Реализация с помощью массива.
Храним указатель на массив,
текущее начало и конец очереди.
Считаем массив зацикленным,
так не потребуется передвигать
элементы .
Можно использовать
динамически растущий буфер.
34
СД «Очередь»
35
//	
  Очередь	
  целых	
  чисел,	
  реализованная	
  с	
  помощью	
  массива.	
  
class	
  CQueue	
  {	
  
public:	
  
	
  	
  	
  	
  CQueue(	
  int	
  size	
  );	
  
	
  	
  	
  	
  ~CQueue()	
  {	
  delete[]	
  buffer;	
  }	
  
	
  
	
  	
  	
  	
  //	
  Добавление	
  и	
  извлечение	
  элемента	
  из	
  очереди.	
  
	
  	
  	
  	
  void	
  Enqueue(	
  int	
  a	
  );	
  
	
  	
  	
  	
  int	
  Dequeue();	
  
	
  
	
  	
  	
  	
  //	
  Проверка	
  на	
  пустоту.	
  
	
  	
  	
  	
  bool	
  IsEmpty()	
  const	
  {	
  return	
  head	
  ==	
  tail;	
  }	
  
	
  
private:	
  
	
  	
  	
  	
  int*	
  buffer;	
  
	
  	
  	
  	
  int	
  bufferSize;	
  
	
  	
  	
  	
  int	
  head;	
  //	
  Указывает	
  на	
  первый	
  элемент	
  очереди.	
  
	
  	
  	
  	
  int	
  tail;	
  //	
  Указывает	
  на	
  следующий	
  после	
  последнего.	
  
};	
  
СД «Очередь»
36
CQueue::CQueue(	
  int	
  size	
  )	
  :	
  
	
  	
  	
  	
  bufferSize(	
  size	
  ),	
  
	
  	
  	
  	
  head(	
  0	
  ),	
  
	
  	
  	
  	
  tail(	
  0	
  )	
  
{	
  
	
  	
  	
  	
  buffer	
  =	
  new	
  int[bufferSize];	
  //	
  Создаем	
  буфер.	
  
}	
  
	
  
//	
  Добавление	
  элемента.	
  
void	
  CQueue::Enqueue(	
  int	
  a	
  )	
  
{	
  
	
  	
  	
  	
  assert(	
  (	
  head	
  –	
  tail	
  +	
  bufferSize	
  )	
  %	
  bufferSize	
  !=	
  1	
  );	
  
	
  	
  	
  	
  buffer[tail++]	
  =	
  a;	
  
	
  	
  	
  	
  if(	
  tail	
  ==	
  bufferSize	
  )	
  
	
  	
  	
  	
  	
  	
  	
  	
  tail	
  =	
  0;	
  
}	
  
//	
  Извлечение	
  элемента.	
  
int	
  CQueue::Dequeue()	
  
{	
  
	
  	
  	
  	
  assert(	
  head	
  !=	
  tail	
  );	
  
	
  	
  	
  	
  int	
  result	
  =	
  buffer[head++];	
  
	
  	
  	
  	
  if(	
  head	
  ==	
  bufferSize	
  )	
  
	
  	
  	
  	
  	
  	
  	
  	
  head	
  =	
  0;	
  
	
  	
  	
  	
  return	
  result;	
  
}	
  
АТД «Дэк»
Определение. Двусвязная очередь – абстрактный тип данных
(структура данных), в которой элементы можно добавлять и удалять как
в начало, так и в конец, то есть принципами обслуживания являются
одновременно FIFO и LIFO.
Операции:
1.  Вставка в конец (PushBack),
2.  Вставка в начало (PushFront),
3.  Извлечение из конца (PopBack),
4.  Извлечение из начала (PopFront).
Дек, также как стек или очередь, можно реализовать с помощью массива или с
помощью списка.
37
СД «Двоичная куча»
Определение. Двоичная куча, пирамида, или сортирующее дерево —
такое почти полное двоичное дерево, для которого выполнены три
условия:
1)  Значение в любой вершине не меньше, чем значения её потомков.
2)  Глубина листьев (расстояние до корня) отличается не более чем на
один слой.
3)  Последний слой заполняется слева направо.
Глубина кучи = 𝑂(​log⁠ 𝑛 ), где n – количество
элементов.
38
СД «Двоичная куча»
Удобная структура данных для двоичной кучи  – массив A. В
массиве последовательно хранятся все элементы кучи «по слоям».
Корень – первый элемент массива, второй и третий элемент –
дочерние элементы и так далее.

39
СД «Двоичная куча»
Такой способ хранения элементов в массиве позволяет
быстро получать дочерние и родительские элементы.
1)  Если индексация элементов массива начинается с 1.
§  A[1] – элемент в корне,
§  потомки элемента A[i] – элементы A[2i] и A[2i + 1].
§  предок элемента A[i] – элемент A[i/2].
2)  Если индексация элементов массива начинается с 0.
§  A[0] – элемент в корне,
§  потомки элемента A[i] – элементы A[2i + 1] и A[2i + 2].
§  предок элемента A[i] – элемент A[(i – 1)/2].
40
СД «Двоичная куча»
41
Если в куче изменяется один из элементов, то она может
перестать удовлетворять свойству упорядоченности.
Для восстановления этого свойства служит процедура Heapify.
Она восстанавливает свойство кучи в дереве, у которого левое и
правое поддеревья удовлетворяют ему.
Если i-й элемент больше, чем его сыновья, всё поддерево уже
является кучей, и делать ничего не надо. В противном случае
меняем местами i-й элемент с наибольшим из его сыновей, после
чего выполняем Heapify для этого сына.
Функция выполняется за время 𝑂(​log⁠ 𝑛 ).
Восстановление свойств кучи
СД «Двоичная куча»
42
//	
  Восстановление	
  свойств	
  кучи.	
  CArray	
  –	
  целочисленный	
  массив.	
  
void	
  Heapify(	
  CArray&	
  arr,	
  int	
  i	
  )	
  
{	
  
	
  	
  	
  	
  int	
  left	
  =	
  2	
  *	
  i	
  +	
  1;	
  
	
  	
  	
  	
  int	
  right	
  =	
  2	
  *	
  i	
  +	
  2;	
  
	
  	
  	
  	
  //	
  Ищем	
  большего	
  сына,	
  если	
  такой	
  есть.	
  
	
  	
  	
  	
  int	
  largest	
  =	
  i;	
  
	
  	
  	
  	
  if(	
  left	
  <	
  arr.Size()	
  &&	
  arr[left]	
  >	
  arr[i]	
  )	
  
	
  	
  	
  	
  	
  	
  	
  	
  largest	
  =	
  left;	
  
	
  	
  	
  	
  if(	
  right	
  <	
  arr.Size()	
  &&	
  arr[right]	
  >	
  arr[largest]	
  )	
  
	
  	
  	
  	
  	
  	
  	
  	
  largest	
  =	
  right;	
  
	
  	
  	
  	
  //	
  Если	
  больший	
  сын	
  есть,	
  то	
  проталкиваем	
  корень	
  в	
  него.	
  
	
  	
  	
  	
  if(	
  largest	
  !=	
  i	
  )	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  std::swap(	
  arr[i],	
  arr[largest]	
  );	
  
	
  	
  	
  	
  	
  	
  	
  	
  Heapify(	
  arr,	
  largest	
  );	
  
	
  	
  	
  	
  }	
  
}	
  
СД «Двоичная куча»
Иллюстрация работы Heapify( A, 2 ).

43
СД «Двоичная куча»
44
Создание кучи из неупорядоченного массива входных данных.
Заметим, что если выполнить Heapify для всех элементов
массива A, начиная с последнего и кончая первым, он станет
кучей. 
Heapify(A, i) не делает ничего, если 𝑖≥ 𝑛/2.
Таким образом, для построения кучи достаточно вызвать Heapify
для всех элементов массива A, начиная с ([​ 𝑛∕2 ]−1)-го и кончая
первым.
Функция выполняется за время 𝑂(𝑛).
Построение кучи
СД «Двоичная куча»
45
//	
  Построение	
  кучи.	
  
void	
  BuildHeap(	
  CArray&	
  arr,	
  int	
  i	
  )	
  
{	
  
	
  	
  	
  	
  for(	
  int	
  i	
  =	
  arr.Size()	
  /	
  2	
  –	
  1;	
  i	
  >=	
  0;	
  -­‐-­‐i	
  )	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  Heapify(	
  arr,	
  i	
  );	
  
	
  	
  	
  	
  }	
  
}	
  
СД «Двоичная куча»
Утверждение. Время работы BuildHeap = O(n).
Доказательство. Время работы Heapify для работы с узлом,
который находится на высоте h, равно O(h).
На любом уровне, находящемся на высоте h, содержится не
более ⌈​ 𝑛∕​2↑ℎ+1  ⌉ узлов.
Общее время работы:
𝑇(𝑛)=∑ℎ=0↑​log⁠ 𝑛 ▒⌈​ 𝑛/​2↑ℎ+1  ⌉𝑂(ℎ) = 𝑂(𝑛∑ℎ=0↑​log⁠ 𝑛 ▒​ℎ/​
2↑ℎ   ).
Воспользуемся формулой ∑ℎ=0↑∞▒​ℎ/​2↑ℎ   =​​1∕2 /​(1−​
1∕2 )↑2  =2.
Таким образом, 𝑇(𝑛)= 𝑂(𝑛∑ℎ=0↑∞▒​ℎ/​2↑ℎ   )= 𝑂(𝑛).
46
СД «Двоичная куча»
47
1.  Добавим элемент в конец кучи.
2.  Восстановим свойство упорядоченности,
проталкивая элемент наверх.
Если элемент больше отца,
мы меняем местами его с отцом.
Если после этого отец больше деда,
мы меняем местами отца с дедом,
и так далее.
Время работы – 𝑂(​log⁠ 𝑛 ).
Добавление элемента
СД «Двоичная куча»
48
//	
  Добавление	
  элемента.	
  
void	
  Add(	
  CArray&	
  arr,	
  int	
  element	
  )	
  
{	
  
	
  	
  	
  	
  arr.Add(	
  element	
  );	
  
	
  	
  	
  	
  int	
  i	
  =	
  arr.Size()	
  –	
  1;	
  
	
  	
  	
  	
  while(	
  i	
  >	
  0	
  )	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  int	
  parent	
  =	
  (	
  i	
  –	
  1	
  )	
  /	
  2;	
  
	
  	
  	
  	
  	
  	
  	
  	
  if(	
  arr[i]	
  <=	
  arr[parent]	
  )	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  return;	
  
	
  	
  	
  	
  	
  	
  	
  	
  std::swap(	
  arr[i],	
  arr[parent]	
  );	
  
	
  	
  	
  	
  	
  	
  	
  	
  i	
  =	
  parent;	
  
	
  	
  	
  	
  }	
  
}	
  
СД «Двоичная куча»
49
Максимальный элемент располагается в корне. Для его
извлечения выполним следующие действия:
1.  Сохраним значение корневого элемента для возврата.
2.  Скопируем последний элемент в корне, удалим последний
элемент.
3.  Вызываем Heapify для корня.
4.  Возвращаем сохраненный корневой элемент.
Время работы – 𝑂(​log⁠ 𝑛 ).
Извлечение максимального элемента
СД «Двоичная куча»
50
//	
  Извлечение	
  максимального	
  элемента.	
  
int	
  ExtractMax(	
  CArray&	
  arr	
  )	
  
{	
  
	
  	
  	
  	
  assert(	
  !arr.IsEmpty()	
  );	
  
	
  	
  	
  	
  //	
  Запоминаем	
  значение	
  корня.	
  
	
  	
  	
  	
  int	
  result	
  =	
  arr[0];	
  
	
  	
  	
  	
  //	
  Переносим	
  последний	
  элемент	
  в	
  корень.	
  
	
  	
  	
  	
  arr[0]	
  =	
  arr.Last();	
  
	
  	
  	
  	
  arr.DeleteLast();	
  
	
  	
  	
  	
  //	
  Вызываем	
  Heapify	
  для	
  корня.	
  
	
  	
  	
  	
  if(	
  !arr.IsEmpty()	
  )	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  Heapify(	
  arr,	
  0	
  );	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  return	
  result;	
  
}	
  
АТД «Очередь с приоритетом»
Определение. Очередь с приоритетом – абстрактный
тип данных, поддерживающий три операции:
1.  InsertWithPriority – добавить в очередь элемент с
нaзначенным приоритетом.
2.  GetNext – извлечь из очереди и вернуть элемент с
наивысшим приоритетом. Другие названия:
«PopElement», «GetMaximum».
3.  PeekAtNext (необязательная операция): просмотреть
элемент с наивысшим приоритетом без извлечения.
51
АТД «Очередь с приоритетом»
АТД «Очередь с приоритетом» может быть реализован с
помощью СД «Двоичная куча».
§  Операции InsertWithPriority соответствует Add.
Время работы – 𝑂(​log⁠ 𝑛 ).
§  Операции GetNext соответствует ExtractMax.
Время работы – 𝑂(​log⁠ 𝑛 ).
§  Операции PeekAtNext соответствует возврат arr[0].
Время работы – 𝑂(1).
52
Итог
Было рассказано на лекции:
§  Структура данных «Динамический массив».
Амортизированное время добавления элемента.
§  Связные списки.
§  Абстрактные типы данных «Стек», «Очередь», «Дек».
Способы реализации.
§  Структура данных «Двоичная куча».
§  Абстрактный тип данных «Очередь с приоритетом».
53
Вопросы?
Спасибо за внимание!

Contenu connexe

Tendances

Лекция 7. Бинарные кучи. Пирамидальная сортировка
Лекция 7. Бинарные кучи. Пирамидальная сортировкаЛекция 7. Бинарные кучи. Пирамидальная сортировка
Лекция 7. Бинарные кучи. Пирамидальная сортировкаMikhail Kurnosov
 
Лекция 4. Стеки и очереди
Лекция 4. Стеки и очередиЛекция 4. Стеки и очереди
Лекция 4. Стеки и очередиMikhail Kurnosov
 
Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)
Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)
Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)Mikhail Kurnosov
 
Лекция 7: Очереди с приоритетами. Бинарные кучи (пирамиды)
Лекция 7: Очереди с приоритетами. Бинарные кучи (пирамиды)Лекция 7: Очереди с приоритетами. Бинарные кучи (пирамиды)
Лекция 7: Очереди с приоритетами. Бинарные кучи (пирамиды)Mikhail Kurnosov
 
Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)
Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)
Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)Mikhail Kurnosov
 
Лекция 4: Стек. Очередь
Лекция 4: Стек. ОчередьЛекция 4: Стек. Очередь
Лекция 4: Стек. ОчередьMikhail Kurnosov
 
Лекция 4. Префиксные деревья (tries, prefix trees)
Лекция 4. Префиксные деревья (tries, prefix trees)Лекция 4. Префиксные деревья (tries, prefix trees)
Лекция 4. Префиксные деревья (tries, prefix trees)Mikhail Kurnosov
 
Java. Интерфейс Map - ассоциативные массивы.
Java. Интерфейс Map - ассоциативные массивы.Java. Интерфейс Map - ассоциативные массивы.
Java. Интерфейс Map - ассоциативные массивы.Unguryan Vitaliy
 
Лекция 7: Бинарные кучи (пирамиды)
Лекция 7: Бинарные кучи (пирамиды)Лекция 7: Бинарные кучи (пирамиды)
Лекция 7: Бинарные кучи (пирамиды)Mikhail Kurnosov
 
C++ Базовый. Занятие 12.
C++ Базовый. Занятие 12.C++ Базовый. Занятие 12.
C++ Базовый. Занятие 12.Igor Shkulipa
 
Лекция 10. Биномиальные кучи (Binomial heaps)
Лекция 10. Биномиальные кучи (Binomial heaps)Лекция 10. Биномиальные кучи (Binomial heaps)
Лекция 10. Биномиальные кучи (Binomial heaps)Mikhail Kurnosov
 
Лекция 3 Элементарные структуры данных Часть 1
Лекция 3 Элементарные структуры данных Часть 1Лекция 3 Элементарные структуры данных Часть 1
Лекция 3 Элементарные структуры данных Часть 1simple_people
 
Лекция 2. Алгоритмы сортировки
Лекция 2. Алгоритмы сортировкиЛекция 2. Алгоритмы сортировки
Лекция 2. Алгоритмы сортировкиMikhail Kurnosov
 
Олег Алистратов — Сортировка списков в Perl и Python
Олег Алистратов — Сортировка списков в Perl и PythonОлег Алистратов — Сортировка списков в Perl и Python
Олег Алистратов — Сортировка списков в Perl и PythonYandex
 
Лекция №7. Поиск. Деревья поиска. Предмет "Структуры и алгоритмы обработки да...
Лекция №7. Поиск. Деревья поиска. Предмет "Структуры и алгоритмы обработки да...Лекция №7. Поиск. Деревья поиска. Предмет "Структуры и алгоритмы обработки да...
Лекция №7. Поиск. Деревья поиска. Предмет "Структуры и алгоритмы обработки да...Nikolay Grebenshikov
 
Лекция 11. Методы разработки алгоритмов
Лекция 11. Методы разработки алгоритмовЛекция 11. Методы разработки алгоритмов
Лекция 11. Методы разработки алгоритмовMikhail Kurnosov
 
Лекция 2. Красно-чёрные деревья (Red-black trees). Скошенные деревья (Splay t...
Лекция 2. Красно-чёрные деревья (Red-black trees). Скошенные деревья (Splay t...Лекция 2. Красно-чёрные деревья (Red-black trees). Скошенные деревья (Splay t...
Лекция 2. Красно-чёрные деревья (Red-black trees). Скошенные деревья (Splay t...Mikhail Kurnosov
 

Tendances (20)

Лекция 7. Бинарные кучи. Пирамидальная сортировка
Лекция 7. Бинарные кучи. Пирамидальная сортировкаЛекция 7. Бинарные кучи. Пирамидальная сортировка
Лекция 7. Бинарные кучи. Пирамидальная сортировка
 
Лекция 4. Стеки и очереди
Лекция 4. Стеки и очередиЛекция 4. Стеки и очереди
Лекция 4. Стеки и очереди
 
Алгоритмы поиска
Алгоритмы поискаАлгоритмы поиска
Алгоритмы поиска
 
Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)
Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)
Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)
 
Лекция 7: Очереди с приоритетами. Бинарные кучи (пирамиды)
Лекция 7: Очереди с приоритетами. Бинарные кучи (пирамиды)Лекция 7: Очереди с приоритетами. Бинарные кучи (пирамиды)
Лекция 7: Очереди с приоритетами. Бинарные кучи (пирамиды)
 
Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)
Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)
Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)
 
Лекция 4: Стек. Очередь
Лекция 4: Стек. ОчередьЛекция 4: Стек. Очередь
Лекция 4: Стек. Очередь
 
Лекция 4. Префиксные деревья (tries, prefix trees)
Лекция 4. Префиксные деревья (tries, prefix trees)Лекция 4. Префиксные деревья (tries, prefix trees)
Лекция 4. Префиксные деревья (tries, prefix trees)
 
Java. Интерфейс Map - ассоциативные массивы.
Java. Интерфейс Map - ассоциативные массивы.Java. Интерфейс Map - ассоциативные массивы.
Java. Интерфейс Map - ассоциативные массивы.
 
Лекция 7: Бинарные кучи (пирамиды)
Лекция 7: Бинарные кучи (пирамиды)Лекция 7: Бинарные кучи (пирамиды)
Лекция 7: Бинарные кучи (пирамиды)
 
C++ Базовый. Занятие 12.
C++ Базовый. Занятие 12.C++ Базовый. Занятие 12.
C++ Базовый. Занятие 12.
 
Лекция 10. Биномиальные кучи (Binomial heaps)
Лекция 10. Биномиальные кучи (Binomial heaps)Лекция 10. Биномиальные кучи (Binomial heaps)
Лекция 10. Биномиальные кучи (Binomial heaps)
 
Лекция 3 Элементарные структуры данных Часть 1
Лекция 3 Элементарные структуры данных Часть 1Лекция 3 Элементарные структуры данных Часть 1
Лекция 3 Элементарные структуры данных Часть 1
 
Лекция 2. Алгоритмы сортировки
Лекция 2. Алгоритмы сортировкиЛекция 2. Алгоритмы сортировки
Лекция 2. Алгоритмы сортировки
 
Олег Алистратов — Сортировка списков в Perl и Python
Олег Алистратов — Сортировка списков в Perl и PythonОлег Алистратов — Сортировка списков в Perl и Python
Олег Алистратов — Сортировка списков в Perl и Python
 
Лекция №7. Поиск. Деревья поиска. Предмет "Структуры и алгоритмы обработки да...
Лекция №7. Поиск. Деревья поиска. Предмет "Структуры и алгоритмы обработки да...Лекция №7. Поиск. Деревья поиска. Предмет "Структуры и алгоритмы обработки да...
Лекция №7. Поиск. Деревья поиска. Предмет "Структуры и алгоритмы обработки да...
 
Рекурсия. Поиск
Рекурсия. ПоискРекурсия. Поиск
Рекурсия. Поиск
 
Основы NumPy
Основы NumPyОсновы NumPy
Основы NumPy
 
Лекция 11. Методы разработки алгоритмов
Лекция 11. Методы разработки алгоритмовЛекция 11. Методы разработки алгоритмов
Лекция 11. Методы разработки алгоритмов
 
Лекция 2. Красно-чёрные деревья (Red-black trees). Скошенные деревья (Splay t...
Лекция 2. Красно-чёрные деревья (Red-black trees). Скошенные деревья (Splay t...Лекция 2. Красно-чёрные деревья (Red-black trees). Скошенные деревья (Splay t...
Лекция 2. Красно-чёрные деревья (Red-black trees). Скошенные деревья (Splay t...
 

En vedette

Алгоритмы и структуры данных осень 2013 лекция 8
Алгоритмы и структуры данных осень 2013 лекция 8Алгоритмы и структуры данных осень 2013 лекция 8
Алгоритмы и структуры данных осень 2013 лекция 8Technopark
 
Лекция 11. Вычислительная модель Pregel
Лекция 11. Вычислительная модель PregelЛекция 11. Вычислительная модель Pregel
Лекция 11. Вычислительная модель PregelTechnopark
 
Java осень 2013 лекция 1-1
Java осень 2013 лекция 1-1Java осень 2013 лекция 1-1
Java осень 2013 лекция 1-1Technopark
 
Java осень 2013 лекция 8
Java осень 2013 лекция 8Java осень 2013 лекция 8
Java осень 2013 лекция 8Technopark
 
Тестирование весна 2014 смешанное занятие 3
Тестирование весна 2014 смешанное занятие 3Тестирование весна 2014 смешанное занятие 3
Тестирование весна 2014 смешанное занятие 3Technopark
 
Лекция 13. YARN
Лекция 13. YARNЛекция 13. YARN
Лекция 13. YARNTechnopark
 
Лекция 14. Hadoop в Поиске Mail.Ru
Лекция 14. Hadoop в Поиске Mail.RuЛекция 14. Hadoop в Поиске Mail.Ru
Лекция 14. Hadoop в Поиске Mail.RuTechnopark
 
Тестирование осень 2013 лекция 4
Тестирование осень 2013 лекция 4Тестирование осень 2013 лекция 4
Тестирование осень 2013 лекция 4Technopark
 
Алгоритмы и структуры данных осень 2013 лекция 6
Алгоритмы и структуры данных осень 2013 лекция 6Алгоритмы и структуры данных осень 2013 лекция 6
Алгоритмы и структуры данных осень 2013 лекция 6Technopark
 
Android осень 2013 лекция 3
Android осень 2013 лекция 3Android осень 2013 лекция 3
Android осень 2013 лекция 3Technopark
 
Алгоритмы и структуры данных осень 2013 лекция 5
Алгоритмы и структуры данных осень 2013 лекция 5Алгоритмы и структуры данных осень 2013 лекция 5
Алгоритмы и структуры данных осень 2013 лекция 5Technopark
 
Android осень 2013 лекция 2
Android осень 2013 лекция 2Android осень 2013 лекция 2
Android осень 2013 лекция 2Technopark
 
Разработка веб-сервисов осень 2013 лекция 1 1
Разработка веб-сервисов осень 2013 лекция 1 1Разработка веб-сервисов осень 2013 лекция 1 1
Разработка веб-сервисов осень 2013 лекция 1 1Technopark
 
Алгоритмы и структуры данных весна 2014 лекция 3
Алгоритмы и структуры данных весна 2014 лекция 3Алгоритмы и структуры данных весна 2014 лекция 3
Алгоритмы и структуры данных весна 2014 лекция 3Technopark
 
Безопасность интернет-приложений осень 2013 лекция 2
Безопасность интернет-приложений осень 2013 лекция 2Безопасность интернет-приложений осень 2013 лекция 2
Безопасность интернет-приложений осень 2013 лекция 2Technopark
 
Frontend весна 2014 лекция 2
Frontend весна 2014 лекция 2Frontend весна 2014 лекция 2
Frontend весна 2014 лекция 2Technopark
 
Java осень 2014 занятие 3
Java осень 2014 занятие 3Java осень 2014 занятие 3
Java осень 2014 занятие 3Technopark
 
Разработка веб-сервисов осень 2013 лекция 9
Разработка веб-сервисов осень 2013 лекция 9Разработка веб-сервисов осень 2013 лекция 9
Разработка веб-сервисов осень 2013 лекция 9Technopark
 
Android осень 2013 лекция 1
Android осень 2013 лекция 1Android осень 2013 лекция 1
Android осень 2013 лекция 1Technopark
 
Безопасность интернет-приложений осень 2013 лекция 10
Безопасность интернет-приложений осень 2013 лекция 10Безопасность интернет-приложений осень 2013 лекция 10
Безопасность интернет-приложений осень 2013 лекция 10Technopark
 

En vedette (20)

Алгоритмы и структуры данных осень 2013 лекция 8
Алгоритмы и структуры данных осень 2013 лекция 8Алгоритмы и структуры данных осень 2013 лекция 8
Алгоритмы и структуры данных осень 2013 лекция 8
 
Лекция 11. Вычислительная модель Pregel
Лекция 11. Вычислительная модель PregelЛекция 11. Вычислительная модель Pregel
Лекция 11. Вычислительная модель Pregel
 
Java осень 2013 лекция 1-1
Java осень 2013 лекция 1-1Java осень 2013 лекция 1-1
Java осень 2013 лекция 1-1
 
Java осень 2013 лекция 8
Java осень 2013 лекция 8Java осень 2013 лекция 8
Java осень 2013 лекция 8
 
Тестирование весна 2014 смешанное занятие 3
Тестирование весна 2014 смешанное занятие 3Тестирование весна 2014 смешанное занятие 3
Тестирование весна 2014 смешанное занятие 3
 
Лекция 13. YARN
Лекция 13. YARNЛекция 13. YARN
Лекция 13. YARN
 
Лекция 14. Hadoop в Поиске Mail.Ru
Лекция 14. Hadoop в Поиске Mail.RuЛекция 14. Hadoop в Поиске Mail.Ru
Лекция 14. Hadoop в Поиске Mail.Ru
 
Тестирование осень 2013 лекция 4
Тестирование осень 2013 лекция 4Тестирование осень 2013 лекция 4
Тестирование осень 2013 лекция 4
 
Алгоритмы и структуры данных осень 2013 лекция 6
Алгоритмы и структуры данных осень 2013 лекция 6Алгоритмы и структуры данных осень 2013 лекция 6
Алгоритмы и структуры данных осень 2013 лекция 6
 
Android осень 2013 лекция 3
Android осень 2013 лекция 3Android осень 2013 лекция 3
Android осень 2013 лекция 3
 
Алгоритмы и структуры данных осень 2013 лекция 5
Алгоритмы и структуры данных осень 2013 лекция 5Алгоритмы и структуры данных осень 2013 лекция 5
Алгоритмы и структуры данных осень 2013 лекция 5
 
Android осень 2013 лекция 2
Android осень 2013 лекция 2Android осень 2013 лекция 2
Android осень 2013 лекция 2
 
Разработка веб-сервисов осень 2013 лекция 1 1
Разработка веб-сервисов осень 2013 лекция 1 1Разработка веб-сервисов осень 2013 лекция 1 1
Разработка веб-сервисов осень 2013 лекция 1 1
 
Алгоритмы и структуры данных весна 2014 лекция 3
Алгоритмы и структуры данных весна 2014 лекция 3Алгоритмы и структуры данных весна 2014 лекция 3
Алгоритмы и структуры данных весна 2014 лекция 3
 
Безопасность интернет-приложений осень 2013 лекция 2
Безопасность интернет-приложений осень 2013 лекция 2Безопасность интернет-приложений осень 2013 лекция 2
Безопасность интернет-приложений осень 2013 лекция 2
 
Frontend весна 2014 лекция 2
Frontend весна 2014 лекция 2Frontend весна 2014 лекция 2
Frontend весна 2014 лекция 2
 
Java осень 2014 занятие 3
Java осень 2014 занятие 3Java осень 2014 занятие 3
Java осень 2014 занятие 3
 
Разработка веб-сервисов осень 2013 лекция 9
Разработка веб-сервисов осень 2013 лекция 9Разработка веб-сервисов осень 2013 лекция 9
Разработка веб-сервисов осень 2013 лекция 9
 
Android осень 2013 лекция 1
Android осень 2013 лекция 1Android осень 2013 лекция 1
Android осень 2013 лекция 1
 
Безопасность интернет-приложений осень 2013 лекция 10
Безопасность интернет-приложений осень 2013 лекция 10Безопасность интернет-приложений осень 2013 лекция 10
Безопасность интернет-приложений осень 2013 лекция 10
 

Similaire à Алгоритмы и структуры данных весна 2014 лекция 2

Java Core. Lecture# 4. Collections.
Java Core. Lecture# 4. Collections.Java Core. Lecture# 4. Collections.
Java Core. Lecture# 4. Collections.Anton Moiseenko
 
Руководство по восстановлению учетных записей в Active Directory
Руководство по восстановлению учетных записей в Active DirectoryРуководство по восстановлению учетных записей в Active Directory
Руководство по восстановлению учетных записей в Active DirectoryAndrey Markin
 
Восстановление учетных записей Active Directory: сборник сценариев
Восстановление учетных записей Active Directory: сборник сценариевВосстановление учетных записей Active Directory: сборник сценариев
Восстановление учетных записей Active Directory: сборник сценариевNetwrix Россия/СНГ
 
Query perfomance tuning
Query perfomance tuningQuery perfomance tuning
Query perfomance tuningcollabock
 
Объектно-ориентированное программирование. Лекции 9 и 10
Объектно-ориентированное программирование. Лекции 9 и 10Объектно-ориентированное программирование. Лекции 9 и 10
Объектно-ориентированное программирование. Лекции 9 и 10Dima Dzuba
 
Оптимизации скорости выполнения запросов
Оптимизации скорости выполнения запросовОптимизации скорости выполнения запросов
Оптимизации скорости выполнения запросовAlex.Kolonitsky
 
C++ Базовый. Занятие 05.
C++ Базовый. Занятие 05.C++ Базовый. Занятие 05.
C++ Базовый. Занятие 05.Igor Shkulipa
 
Python и его тормоза
Python и его тормозаPython и его тормоза
Python и его тормозаAlexander Shigin
 
Массивы в Java
Массивы в JavaМассивы в Java
Массивы в Javametaform
 
Sergii Tsypanov "Performance 1001 Tips"
Sergii Tsypanov "Performance 1001 Tips"Sergii Tsypanov "Performance 1001 Tips"
Sergii Tsypanov "Performance 1001 Tips"LogeekNightUkraine
 
AlgoCollections (RUS)
AlgoCollections (RUS)AlgoCollections (RUS)
AlgoCollections (RUS)Anton Bukov
 
Встреча №9. Алгоритмы и коллекции стандартных библиотек C++, C#, Java, Object...
Встреча №9. Алгоритмы и коллекции стандартных библиотек C++, C#, Java, Object...Встреча №9. Алгоритмы и коллекции стандартных библиотек C++, C#, Java, Object...
Встреча №9. Алгоритмы и коллекции стандартных библиотек C++, C#, Java, Object...CocoaHeads
 

Similaire à Алгоритмы и структуры данных весна 2014 лекция 2 (20)

Java Core. Lecture# 4. Collections.
Java Core. Lecture# 4. Collections.Java Core. Lecture# 4. Collections.
Java Core. Lecture# 4. Collections.
 
Lec 4
Lec 4Lec 4
Lec 4
 
Руководство по восстановлению учетных записей в Active Directory
Руководство по восстановлению учетных записей в Active DirectoryРуководство по восстановлению учетных записей в Active Directory
Руководство по восстановлению учетных записей в Active Directory
 
Восстановление учетных записей Active Directory: сборник сценариев
Восстановление учетных записей Active Directory: сборник сценариевВосстановление учетных записей Active Directory: сборник сценариев
Восстановление учетных записей Active Directory: сборник сценариев
 
Query perfomance tuning
Query perfomance tuningQuery perfomance tuning
Query perfomance tuning
 
Объектно-ориентированное программирование. Лекции 9 и 10
Объектно-ориентированное программирование. Лекции 9 и 10Объектно-ориентированное программирование. Лекции 9 и 10
Объектно-ориентированное программирование. Лекции 9 и 10
 
Javascript
JavascriptJavascript
Javascript
 
Scala - my path
Scala - my pathScala - my path
Scala - my path
 
Оптимизации скорости выполнения запросов
Оптимизации скорости выполнения запросовОптимизации скорости выполнения запросов
Оптимизации скорости выполнения запросов
 
Underscore js
Underscore jsUnderscore js
Underscore js
 
C++ Базовый. Занятие 05.
C++ Базовый. Занятие 05.C++ Базовый. Занятие 05.
C++ Базовый. Занятие 05.
 
Python и его тормоза
Python и его тормозаPython и его тормоза
Python и его тормоза
 
Массивы в Java
Массивы в JavaМассивы в Java
Массивы в Java
 
Sergii Tsypanov "Performance 1001 Tips"
Sergii Tsypanov "Performance 1001 Tips"Sergii Tsypanov "Performance 1001 Tips"
Sergii Tsypanov "Performance 1001 Tips"
 
Jquery
JqueryJquery
Jquery
 
Administrarea DSpace
Administrarea DSpaceAdministrarea DSpace
Administrarea DSpace
 
Vba 06
Vba 06Vba 06
Vba 06
 
AlgoCollections (RUS)
AlgoCollections (RUS)AlgoCollections (RUS)
AlgoCollections (RUS)
 
Collections
CollectionsCollections
Collections
 
Встреча №9. Алгоритмы и коллекции стандартных библиотек C++, C#, Java, Object...
Встреча №9. Алгоритмы и коллекции стандартных библиотек C++, C#, Java, Object...Встреча №9. Алгоритмы и коллекции стандартных библиотек C++, C#, Java, Object...
Встреча №9. Алгоритмы и коллекции стандартных библиотек C++, C#, Java, Object...
 

Plus de Technopark

Лекция 12. Spark
Лекция 12. SparkЛекция 12. Spark
Лекция 12. SparkTechnopark
 
Лекция 10. Apache Mahout
Лекция 10. Apache MahoutЛекция 10. Apache Mahout
Лекция 10. Apache MahoutTechnopark
 
Лекция 9. ZooKeeper
Лекция 9. ZooKeeperЛекция 9. ZooKeeper
Лекция 9. ZooKeeperTechnopark
 
Лекция 7. Введение в Pig и Hive
Лекция 7. Введение в Pig и HiveЛекция 7. Введение в Pig и Hive
Лекция 7. Введение в Pig и HiveTechnopark
 
Лекция 6. MapReduce в Hadoop (графы)
Лекция 6. MapReduce в Hadoop (графы)Лекция 6. MapReduce в Hadoop (графы)
Лекция 6. MapReduce в Hadoop (графы)Technopark
 
Лекция 5. MapReduce в Hadoop (алгоритмы)
Лекция 5. MapReduce в Hadoop (алгоритмы)Лекция 5. MapReduce в Hadoop (алгоритмы)
Лекция 5. MapReduce в Hadoop (алгоритмы)Technopark
 
Лекция 4. MapReduce в Hadoop (введение)
Лекция 4. MapReduce в Hadoop (введение)Лекция 4. MapReduce в Hadoop (введение)
Лекция 4. MapReduce в Hadoop (введение)Technopark
 
Лекция 3. Распределённая файловая система HDFS
Лекция 3. Распределённая файловая система HDFSЛекция 3. Распределённая файловая система HDFS
Лекция 3. Распределённая файловая система HDFSTechnopark
 
Лекция 2. Основы Hadoop
Лекция 2. Основы HadoopЛекция 2. Основы Hadoop
Лекция 2. Основы HadoopTechnopark
 
Лекция 1. Введение в Big Data и MapReduce
Лекция 1. Введение в Big Data и MapReduceЛекция 1. Введение в Big Data и MapReduce
Лекция 1. Введение в Big Data и MapReduceTechnopark
 
СУБД 2013 Лекция №10 "Нереляционное решение в области баз данных — NoSQL"
СУБД 2013 Лекция №10 "Нереляционное решение в области баз данных — NoSQL"СУБД 2013 Лекция №10 "Нереляционное решение в области баз данных — NoSQL"
СУБД 2013 Лекция №10 "Нереляционное решение в области баз данных — NoSQL"Technopark
 
СУБД 2013 Лекция №10 "Нереляционное решение в области баз данных — NoSQL" Час...
СУБД 2013 Лекция №10 "Нереляционное решение в области баз данных — NoSQL" Час...СУБД 2013 Лекция №10 "Нереляционное решение в области баз данных — NoSQL" Час...
СУБД 2013 Лекция №10 "Нереляционное решение в области баз данных — NoSQL" Час...Technopark
 
СУБД 2013 Лекция №9 "Безопасность баз данных"
СУБД 2013 Лекция №9 "Безопасность баз данных"СУБД 2013 Лекция №9 "Безопасность баз данных"
СУБД 2013 Лекция №9 "Безопасность баз данных"Technopark
 
СУБД 2013 Лекция №8 "Конфигурирование базы данных"
СУБД 2013 Лекция №8 "Конфигурирование базы данных"СУБД 2013 Лекция №8 "Конфигурирование базы данных"
СУБД 2013 Лекция №8 "Конфигурирование базы данных"Technopark
 
СУБД 2013 Лекция №7 "Оптимизация запросов и индексирование"
СУБД 2013 Лекция №7 "Оптимизация запросов и индексирование"СУБД 2013 Лекция №7 "Оптимизация запросов и индексирование"
СУБД 2013 Лекция №7 "Оптимизация запросов и индексирование"Technopark
 
СУБД 2013 Лекция №5 "Определение узких мест"
СУБД 2013 Лекция №5 "Определение узких мест"СУБД 2013 Лекция №5 "Определение узких мест"
СУБД 2013 Лекция №5 "Определение узких мест"Technopark
 
СУБД 2013 Лекция №6 "Профилирование запросов. Сложноструктурированные SQL-зап...
СУБД 2013 Лекция №6 "Профилирование запросов. Сложноструктурированные SQL-зап...СУБД 2013 Лекция №6 "Профилирование запросов. Сложноструктурированные SQL-зап...
СУБД 2013 Лекция №6 "Профилирование запросов. Сложноструктурированные SQL-зап...Technopark
 
СУБД 2013 Лекция №4 "Расширенные возможности работы с базами данных. Триггеры...
СУБД 2013 Лекция №4 "Расширенные возможности работы с базами данных. Триггеры...СУБД 2013 Лекция №4 "Расширенные возможности работы с базами данных. Триггеры...
СУБД 2013 Лекция №4 "Расширенные возможности работы с базами данных. Триггеры...Technopark
 
СУБД 2013 Лекция №3 "Выборка данных (продолжение). Транзакции"
СУБД 2013 Лекция №3 "Выборка данных (продолжение). Транзакции"СУБД 2013 Лекция №3 "Выборка данных (продолжение). Транзакции"
СУБД 2013 Лекция №3 "Выборка данных (продолжение). Транзакции"Technopark
 
СУБД 2013 Лекция №2 "Модификация данных. Выборка данных (начало)"
СУБД 2013 Лекция №2 "Модификация данных. Выборка данных (начало)"СУБД 2013 Лекция №2 "Модификация данных. Выборка данных (начало)"
СУБД 2013 Лекция №2 "Модификация данных. Выборка данных (начало)"Technopark
 

Plus de Technopark (20)

Лекция 12. Spark
Лекция 12. SparkЛекция 12. Spark
Лекция 12. Spark
 
Лекция 10. Apache Mahout
Лекция 10. Apache MahoutЛекция 10. Apache Mahout
Лекция 10. Apache Mahout
 
Лекция 9. ZooKeeper
Лекция 9. ZooKeeperЛекция 9. ZooKeeper
Лекция 9. ZooKeeper
 
Лекция 7. Введение в Pig и Hive
Лекция 7. Введение в Pig и HiveЛекция 7. Введение в Pig и Hive
Лекция 7. Введение в Pig и Hive
 
Лекция 6. MapReduce в Hadoop (графы)
Лекция 6. MapReduce в Hadoop (графы)Лекция 6. MapReduce в Hadoop (графы)
Лекция 6. MapReduce в Hadoop (графы)
 
Лекция 5. MapReduce в Hadoop (алгоритмы)
Лекция 5. MapReduce в Hadoop (алгоритмы)Лекция 5. MapReduce в Hadoop (алгоритмы)
Лекция 5. MapReduce в Hadoop (алгоритмы)
 
Лекция 4. MapReduce в Hadoop (введение)
Лекция 4. MapReduce в Hadoop (введение)Лекция 4. MapReduce в Hadoop (введение)
Лекция 4. MapReduce в Hadoop (введение)
 
Лекция 3. Распределённая файловая система HDFS
Лекция 3. Распределённая файловая система HDFSЛекция 3. Распределённая файловая система HDFS
Лекция 3. Распределённая файловая система HDFS
 
Лекция 2. Основы Hadoop
Лекция 2. Основы HadoopЛекция 2. Основы Hadoop
Лекция 2. Основы Hadoop
 
Лекция 1. Введение в Big Data и MapReduce
Лекция 1. Введение в Big Data и MapReduceЛекция 1. Введение в Big Data и MapReduce
Лекция 1. Введение в Big Data и MapReduce
 
СУБД 2013 Лекция №10 "Нереляционное решение в области баз данных — NoSQL"
СУБД 2013 Лекция №10 "Нереляционное решение в области баз данных — NoSQL"СУБД 2013 Лекция №10 "Нереляционное решение в области баз данных — NoSQL"
СУБД 2013 Лекция №10 "Нереляционное решение в области баз данных — NoSQL"
 
СУБД 2013 Лекция №10 "Нереляционное решение в области баз данных — NoSQL" Час...
СУБД 2013 Лекция №10 "Нереляционное решение в области баз данных — NoSQL" Час...СУБД 2013 Лекция №10 "Нереляционное решение в области баз данных — NoSQL" Час...
СУБД 2013 Лекция №10 "Нереляционное решение в области баз данных — NoSQL" Час...
 
СУБД 2013 Лекция №9 "Безопасность баз данных"
СУБД 2013 Лекция №9 "Безопасность баз данных"СУБД 2013 Лекция №9 "Безопасность баз данных"
СУБД 2013 Лекция №9 "Безопасность баз данных"
 
СУБД 2013 Лекция №8 "Конфигурирование базы данных"
СУБД 2013 Лекция №8 "Конфигурирование базы данных"СУБД 2013 Лекция №8 "Конфигурирование базы данных"
СУБД 2013 Лекция №8 "Конфигурирование базы данных"
 
СУБД 2013 Лекция №7 "Оптимизация запросов и индексирование"
СУБД 2013 Лекция №7 "Оптимизация запросов и индексирование"СУБД 2013 Лекция №7 "Оптимизация запросов и индексирование"
СУБД 2013 Лекция №7 "Оптимизация запросов и индексирование"
 
СУБД 2013 Лекция №5 "Определение узких мест"
СУБД 2013 Лекция №5 "Определение узких мест"СУБД 2013 Лекция №5 "Определение узких мест"
СУБД 2013 Лекция №5 "Определение узких мест"
 
СУБД 2013 Лекция №6 "Профилирование запросов. Сложноструктурированные SQL-зап...
СУБД 2013 Лекция №6 "Профилирование запросов. Сложноструктурированные SQL-зап...СУБД 2013 Лекция №6 "Профилирование запросов. Сложноструктурированные SQL-зап...
СУБД 2013 Лекция №6 "Профилирование запросов. Сложноструктурированные SQL-зап...
 
СУБД 2013 Лекция №4 "Расширенные возможности работы с базами данных. Триггеры...
СУБД 2013 Лекция №4 "Расширенные возможности работы с базами данных. Триггеры...СУБД 2013 Лекция №4 "Расширенные возможности работы с базами данных. Триггеры...
СУБД 2013 Лекция №4 "Расширенные возможности работы с базами данных. Триггеры...
 
СУБД 2013 Лекция №3 "Выборка данных (продолжение). Транзакции"
СУБД 2013 Лекция №3 "Выборка данных (продолжение). Транзакции"СУБД 2013 Лекция №3 "Выборка данных (продолжение). Транзакции"
СУБД 2013 Лекция №3 "Выборка данных (продолжение). Транзакции"
 
СУБД 2013 Лекция №2 "Модификация данных. Выборка данных (начало)"
СУБД 2013 Лекция №2 "Модификация данных. Выборка данных (начало)"СУБД 2013 Лекция №2 "Модификация данных. Выборка данных (начало)"
СУБД 2013 Лекция №2 "Модификация данных. Выборка данных (начало)"
 

Алгоритмы и структуры данных весна 2014 лекция 2

  • 2. План лекции 2 §  Структура данных «Динамический массив». Амортизированное время добавления элемента. §  Однонаправленные, двунаправленные списки. §  Поиск, добавление элементов, слияние списков. §  Абстрактные типы данных «Стек», «Очередь», «Дек». Способы реализации. §  Структура данных «Двоичная куча». §  Абстрактный тип данных «Очередь с приоритетом». 2
  • 3. Абстрактные типы данных и структуры данных Определение. Абстрактный тип данных (АТД) – это тип данных, который предоставляет для работы с элементами этого типа определённый набор функций, а также возможность создавать элементы этого типа при помощи специальных функций. Вся внутренняя структура такого типа спрятана – в этом и заключается суть абстракции. 3
  • 4. Абстрактные типы данных и структуры данных Напоминание. Структура данных – программная единица, позволяющая хранить и обрабатывать множество однотипных и/или логически связанных данных. Абстрактный тип данных определяет набор функций, независимых от конкретной реализации типа, для оперирования его значениями. Конкретные реализации АТД будем также называть структурами данных. 4
  • 5. СД «Массив» Напоминание. Массив – набор однотипных компонентов (элементов), расположенных в памяти непосредственно друг за другом, доступ к которым осуществляется по индексу (индексам). Традиционно индексирование элементов массива начинают с 0. 5 20 34 11 563 23 -1 2 0 -33 7 0 1 2 3 4 5 6 7 8 9
  • 6. СД «Массив» 6 //  Создание  массивов  в  C++:     //  Массив  из  10  целых  чисел.  Создается  на  стеке  потока.   int  intArray1[10];     //  Массив  из  заранее  неизвестного  количества  целых  чисел.   //  Создается  в  куче  процесса.   //  Такие  массивы  называют  массивами  переменной  длины.   int  n  =  0;   cin  >>  n;   int*  intArray2  =  new  int[n];   delete[]  intArray2;
  • 7. СД «Динамический массив» Определение. СД «Динамический массив» – структура данных с операциями §  Добавление элемента в конец массива «Add» (или PushBack), §  Доступ к элементу массива по индексу за 𝑂(1) «GetAt» (или оператор []). 7
  • 8. СД «Динамический массив» Динамический массив содержит внутренний массив фиксированной длины для хранения элементов. Внутренний массив называется буфером. Помнит текущее количество добавленных элементов. Размер буфера имеет некоторый запас для возможности добавления новых элементов. Пример. Буфер размера 14 заполнен 10 элементами. 8 Т е х н о п а р к ! 0 1 2 3 4 5 6 7 8 9 10 11 12 13
  • 9. СД «Динамический массив» Буфер может закончиться… Если буфер закончился, то при добавлении нового элемента: §  выделим новый буфер, больший исходного; §  скопируем содержимое старого буфера в новый; §  добавим новый элемент. 9 Т е х н о п а 0 1 2 3 4 5 6 Т е х н о п а р 0 1 2 3 4 5 6 7 8 9 10 11 12 13
  • 10. СД «Динамический массив» 10 //  Структура,  описывающая  массив  чисел  с  плавающей  точкой.   struct  CArray1  {          double*  Buffer;          int  BufferSize;          int  RealSize;            CArray()  :  Buffer(  0  ),  BufferSize(  0  ),  RealSize(  0  )  {}   };     //  Доступ  к  элементу  массива  по  индексу.   double  GetAt(  const  CArray1&  arr,  int  index  )   {          assert(  index  >=  0  &&  index  <  arr.RealSize  &&  arr.Buffer  !=  0  );          return  arr.Buffer[index];   }  
  • 11. СД «Динамический массив» 11 //  Увеличение  буфера.   void  grow(  CArray1&  arr  )   {          //  Создаем  новый  буфер.          int  newBufferSize  =  arr.BufferSize  *  2;          double*  newBuffer  =  new  double[newBufferSize];          //  Копируем.          for(  int  i  =  0;  i  <  arr.RealSize;  ++i  )                  newBuffer[i]  =  arr.Buffer[i];          //  Чистим  старый  буфер.          delete[]  arr.Buffer;          arr.Buffer  =  newBuffer;          arr.BufferSize  =  newBufferSize;   }   //  Добавление  нового  элемента.   void  Add(  CArray1&  arr,  double  element  )   {          if(  arr.RealSize  ==  arr.BufferSize  )                  grow(  arr  );          assert(  arr.RealSize  <  arr.BufferSize  &&  arr.Buffer  !=  0  );          arr.Buffer[arr.RealSize++]  =  element;   }  
  • 12. СД «Динамический массив» Как долго работает функция Add добавления элемента? §  В лучшем случае = 𝑂(1) §  В худшем случае = 𝑂(𝑛) §  В среднем? Имеет смысл рассматривать несколько операций добавления и оценить среднее время в контексте последовательности операций. Подобный анализ называется амортизационным. 12
  • 13. Амортизационный анализ Определение (по Кормену…). При амортизационном анализе время, требуемое для выполнения последовательности операций над структурой данных, усредняется по всем выполняемым операциям. Этот анализ можно использовать, например, чтобы показать, что даже если одна из операций последовательности является дорогостоящей, то при усреднении по всей последовательности средняя стоимость операций будет небольшой. 13
  • 14. Амортизационный анализ Амортизационный анализ отличается от анализа средних величин тем, что в нем не учитывается вероятность. При амортизационном анализе гарантируется средняя производительность операций в наихудшем случае. 14
  • 15. Амортизационный анализ Определение. Пусть S(n) – время выполнения последовательности всех n операций в наихудшем случае. Амортизированной стоимостью (временем) называется среднее время, приходящееся на одну операцию ​ 𝑆(𝑛)⁄𝑛 . Оценим амортизированную стоимость операций Add динамического массива. 15
  • 16. СД «Динамический массив» Утверждение. Пусть в реализации функции grow() буфер удваивается. Тогда амортизированная стоимость функции Add составляет 𝑂(1). Доказательство. Рассмотрим последовательность из n операций Add. Обозначим 𝑃(𝑘) - время выполнения Add в случае, когда RealSize = k. §  𝑃(𝑘)=​ 𝑐↓1 𝑘, если 𝑘=​2↑𝑚 . §  𝑃(𝑘)=​ 𝑐↓2 , если 𝑘≠​2↑𝑚 . 𝑆(𝑛)=∑𝑘=1↑𝑛▒𝑃(𝑘) ≤​ 𝑐↓1 ∑𝑚:​2↑𝑚 < 𝑛↑▒​2↑𝑚  +​ 𝑐↓2 ∑𝑘: 𝑘≠​ 2↑𝑚 ↑▒1 = 𝑂(𝑛). Амортизированное время 𝑇(𝑛)=​ 𝑆(𝑛)⁄𝑛 =​ 𝑂(𝑛)⁄𝑛 = 𝑂(1). 16
  • 17. СД «Динамический массив» 17 //  Класс  «Динамический  массив».   class  CArray  {   public:          CArray()  :  buffer(  0  ),  bufferSize(  0  ),  realSize(  0  )  {}          ~CArray()  {  delete[]  buffer;  }            //  Доступ  по  индексу.          double  GetAt(  int  index  )  const;          double  operator[](  int  index  )  const  {  return  GetAt(  index  );  }          double&  operator[](  int  index  );            //  Добавление  нового  элемента.          void  Add(  double  element  );     private:          double*  buffer;  //  Буфер.          int  bufferSize;  //  Размер  буфера.          int  realSize;  //  Количество  элементов  в  массиве.            void  grow();   };    
  • 18. СД «Динамический массив» 18 //  Доступ  к  элементу.   double  CArray::GetAt(  int  index  )   {          assert(  index  >=  0  &&  index  <  realSize  &&  buffer  !=  0  );          return  buffer[index];   }   //  Увеличение  буфера.   void  CArray::grow()   {          int  newBufferSize  =  bufferSize  *  2;          double*  newBuffer  =  new  double[newBufferSize];          for(  int  i  =  0;  i  <  realSize;  ++i  )                  newBuffer[i]  =  buffer[i];          delete[]  buffer;          buffer  =  newBuffer;          bufferSize  =  newBufferSize;   }   //  Добавление  элемента.   void  CArray::Add(  double  element  )   {          if(  realSize  ==  bufferSize  )                  grow(  arr  );          assert(  realSize  <  bufferSize  &&  buffer  !=  0  );          buffer[realSize++]  =  element;   }  
  • 19. Связные списки Определение. Связный список - динамическая структура данных, состоящая из узлов, каждый из которых содержит как собственно данные, так и одну или две ссылки («связки») на следующий и/ или предыдущий узел списка. Преимущество перед массивом: §  Порядок элементов списка может не совпадать с порядком расположения элементов данных в памяти, а порядок обхода списка всегда явно задаётся его внутренними связями. 19
  • 20. Связные списки Односвязный список (однонаправленный связный список) Здесь ссылка в каждом узле указывает на следующий узел в списке. В односвязном списке можно передвигаться только в сторону конца списка. Узнать адрес предыдущего элемента, опираясь на содержимое текущего узла, невозможно. 20
  • 21. Связные списки Двусвязный список (Двунаправленный связный список) Здесь ссылки в каждом узле указывают на предыдущий и на последующий узел в списке. По двусвязному списку можно передвигаться в любом направлении – как к началу, так и к концу. В этом списке проще производить удаление и перестановку элементов, так как всегда известны адреса тех элементов списка, указатели которых направлены на изменяемый элемент. 21
  • 22. Связные списки Операции со списками: §  Поиск элемента, §  Вставка элемента, §  Удаление элемента, §  Объединение списков, §  … 22
  • 23. Связные списки 23 //  Элемент  двусвязного  списка  с  целочисленными   //  значениями.   struct  CNode  {          int  Data;          CNode*  Next;          CNode*  Prev;            CNode()  :  Data(  0  ),  Next(  0  ),  Prev(  0  )  {}   };      
  • 24. Связные списки 24 //  Линейный  поиск  элемента  «a»  в  списке.   //  Возвращает  0,  если  элемент  не  найден.   СNode*  Search(  CNode*  head,  int  a  )   {          CNode*  current  =  head;          while(  current  !=  0  )  {                  if(  current-­‐>Data  ==  a  )                          return  current;                  current  =  current-­‐>Next;          }          return  0;   }     Время работы в худшем случае = O(n), где n – длина списка.
  • 25. Связные списки 25 //  Вставка  элемента  «a»  после  текущего.   СNode*  InsertAfter(  CNode*  node,  int  a  )   {          assert(  node  !=  0  );          //  Создаем  новый  элемент.          CNode*  newNode  =  new  CNode();          newNode-­‐>Data  =  a;          newNode-­‐>Next  =  node-­‐>Next;          newNode-­‐>Prev  =  node;          //  Обновляем  Prev  следующего  элемента,  если  он  есть.          if(  node-­‐>Next  !=  0  )  {                  node-­‐>Next-­‐>Prev  =  newNode;          }          //  Обновляем  Next  текущего  элемента.          node-­‐>Next  =  newNode;          return  newNode;   }     Время работы = O(1).
  • 26. Связные списки 26 //  Удаление  элемента.   void  DeleteAt(  CNode*  node  )   {          assert(  node  !=  0  );          //  Обновляем  Prev  следующего  элемента,  если  он  есть.          if(  node-­‐>Next  !=  0  )  {                  node-­‐>Next-­‐>Prev  =  node-­‐>Prev;          }          //  Обновляем  Next  предыдущего  элемента,  если  он  есть.          if(  node-­‐>Prev  !=  0  )  {                  node-­‐>Prev-­‐>Next  =  node-­‐>Next;          }          delete  node;   }     Время работы = O(1).
  • 27. Связные списки 27 //  Объединение  списков.  К  списку  1  подцепляем  список  2.   void  Union(  CNode*  head1,  CNode*  head2  )   {          assert(  head1  !=  0  &&  head2  !=  0  );          //  Идем  в  хвост  списка  1.          CNode*  tail1  =  head1;          for(  ;  tail1-­‐>Next  !=  0;  tail1  =  tail1-­‐>Next  );          //  Обновляем  Next  хвоста.          tail1-­‐>Next  =  head2;          //  Обновляем  Prev  головы  второго  списка.          head2-­‐>Prev  =  tail1;   }     Время работы = O(n), где n – длина первого списка.
  • 28. Связные списки Недостатки списков: §  Сложность определения элемента по его номеру (индексу). §  На поля указатели расходуется дополнительная память. §  Элементы списка могут располагаться в памяти разреженно, что оказывает негативный эффект на кэширование процессора. Преимущества списков перед массивом: §  Быстрая вставка элемента в любом месте списка. В том числе в начало и в конец, если имеются соответствующие указатели. §  Быстрое удаление любого элемента. В том числе в начало и в конец, если имеются соответствующие указатели. 28
  • 29. АТД «Стек» Определение. Стек – абстрактный тип данных (или структура данных), представляющий из себя список элементов, организованный по принципу LIFO = Last In First Out, «последним пришел, первым вышел». Операции: 1.  Вставка (Push) 2.  Извлечение (Pop) – извлечение элемента, добавленного последним. 29
  • 30. СД «Стек» Стек можно реализовать с помощью массива или с помощью списка. Реализация с помощью массива. Храним указатель на массив и текущее количество элементов в стеке. Можно использовать динамический массив. 30
  • 31. СД «Стек» 31 //  Стек  целых  чисел,  реализованный  с  помощью  массива.   class  CStack  {   public:          CStack(  int  size  );          ~CStack();            //  Добавление  и  извлечение  элемента  из  стека.          void  Push(  int  a  );          int  Pop();            //  Проверка  на  пустоту.          bool  IsEmpty()  const  {  return  top  ==  -­‐1;  }     private:          int*  buffer;          int  bufferSize;          int  top;   };  
  • 32. СД «Стек» 32 //  В  конструкторе  создаем  буфер.   CStack::CStack(  int  size  )  :          bufferSize(  size  ),          top(  -­‐1  )   {          buffer  =  new  int[bufferSize];   }   //  В  деструкторе  удаляем  буфер.   CStack::~CStack()   {          delete[]  buffer;   }     //  Добавление  элемента.   void  CStack::Push(  int  a  )   {          assert(  top  +  1  <  bufferSize  );          buffer[++top]  =  a;   }   //  Извлечение  элемента.   int  CStack::Pop()   {          assert(  top  !=  -­‐1  );          return  buffer[top-­‐-­‐];   }  
  • 33. АТД «Очередь» Определение. Очередь – абстрактный тип данных (или структура данных), представляющий из себя список элементов, организованный по принципу FIFO = First In First Out, «первым пришел, первым вышел». Операции: 1.  Вставка (Enqueue) 2.  Извлечение (Dequeue) – извлечение элемента, добавленного первым. 33
  • 34. СД «Очередь» Очередь также как и стек можно реализовать с помощью массива или с помощью списка. Реализация с помощью массива. Храним указатель на массив, текущее начало и конец очереди. Считаем массив зацикленным, так не потребуется передвигать элементы . Можно использовать динамически растущий буфер. 34
  • 35. СД «Очередь» 35 //  Очередь  целых  чисел,  реализованная  с  помощью  массива.   class  CQueue  {   public:          CQueue(  int  size  );          ~CQueue()  {  delete[]  buffer;  }            //  Добавление  и  извлечение  элемента  из  очереди.          void  Enqueue(  int  a  );          int  Dequeue();            //  Проверка  на  пустоту.          bool  IsEmpty()  const  {  return  head  ==  tail;  }     private:          int*  buffer;          int  bufferSize;          int  head;  //  Указывает  на  первый  элемент  очереди.          int  tail;  //  Указывает  на  следующий  после  последнего.   };  
  • 36. СД «Очередь» 36 CQueue::CQueue(  int  size  )  :          bufferSize(  size  ),          head(  0  ),          tail(  0  )   {          buffer  =  new  int[bufferSize];  //  Создаем  буфер.   }     //  Добавление  элемента.   void  CQueue::Enqueue(  int  a  )   {          assert(  (  head  –  tail  +  bufferSize  )  %  bufferSize  !=  1  );          buffer[tail++]  =  a;          if(  tail  ==  bufferSize  )                  tail  =  0;   }   //  Извлечение  элемента.   int  CQueue::Dequeue()   {          assert(  head  !=  tail  );          int  result  =  buffer[head++];          if(  head  ==  bufferSize  )                  head  =  0;          return  result;   }  
  • 37. АТД «Дэк» Определение. Двусвязная очередь – абстрактный тип данных (структура данных), в которой элементы можно добавлять и удалять как в начало, так и в конец, то есть принципами обслуживания являются одновременно FIFO и LIFO. Операции: 1.  Вставка в конец (PushBack), 2.  Вставка в начало (PushFront), 3.  Извлечение из конца (PopBack), 4.  Извлечение из начала (PopFront). Дек, также как стек или очередь, можно реализовать с помощью массива или с помощью списка. 37
  • 38. СД «Двоичная куча» Определение. Двоичная куча, пирамида, или сортирующее дерево — такое почти полное двоичное дерево, для которого выполнены три условия: 1)  Значение в любой вершине не меньше, чем значения её потомков. 2)  Глубина листьев (расстояние до корня) отличается не более чем на один слой. 3)  Последний слой заполняется слева направо. Глубина кучи = 𝑂(​log⁠ 𝑛 ), где n – количество элементов. 38
  • 39. СД «Двоичная куча» Удобная структура данных для двоичной кучи  – массив A. В массиве последовательно хранятся все элементы кучи «по слоям». Корень – первый элемент массива, второй и третий элемент – дочерние элементы и так далее. 39
  • 40. СД «Двоичная куча» Такой способ хранения элементов в массиве позволяет быстро получать дочерние и родительские элементы. 1)  Если индексация элементов массива начинается с 1. §  A[1] – элемент в корне, §  потомки элемента A[i] – элементы A[2i] и A[2i + 1]. §  предок элемента A[i] – элемент A[i/2]. 2)  Если индексация элементов массива начинается с 0. §  A[0] – элемент в корне, §  потомки элемента A[i] – элементы A[2i + 1] и A[2i + 2]. §  предок элемента A[i] – элемент A[(i – 1)/2]. 40
  • 41. СД «Двоичная куча» 41 Если в куче изменяется один из элементов, то она может перестать удовлетворять свойству упорядоченности. Для восстановления этого свойства служит процедура Heapify. Она восстанавливает свойство кучи в дереве, у которого левое и правое поддеревья удовлетворяют ему. Если i-й элемент больше, чем его сыновья, всё поддерево уже является кучей, и делать ничего не надо. В противном случае меняем местами i-й элемент с наибольшим из его сыновей, после чего выполняем Heapify для этого сына. Функция выполняется за время 𝑂(​log⁠ 𝑛 ). Восстановление свойств кучи
  • 42. СД «Двоичная куча» 42 //  Восстановление  свойств  кучи.  CArray  –  целочисленный  массив.   void  Heapify(  CArray&  arr,  int  i  )   {          int  left  =  2  *  i  +  1;          int  right  =  2  *  i  +  2;          //  Ищем  большего  сына,  если  такой  есть.          int  largest  =  i;          if(  left  <  arr.Size()  &&  arr[left]  >  arr[i]  )                  largest  =  left;          if(  right  <  arr.Size()  &&  arr[right]  >  arr[largest]  )                  largest  =  right;          //  Если  больший  сын  есть,  то  проталкиваем  корень  в  него.          if(  largest  !=  i  )  {                  std::swap(  arr[i],  arr[largest]  );                  Heapify(  arr,  largest  );          }   }  
  • 44. СД «Двоичная куча» 44 Создание кучи из неупорядоченного массива входных данных. Заметим, что если выполнить Heapify для всех элементов массива A, начиная с последнего и кончая первым, он станет кучей.  Heapify(A, i) не делает ничего, если 𝑖≥ 𝑛/2. Таким образом, для построения кучи достаточно вызвать Heapify для всех элементов массива A, начиная с ([​ 𝑛∕2 ]−1)-го и кончая первым. Функция выполняется за время 𝑂(𝑛). Построение кучи
  • 45. СД «Двоичная куча» 45 //  Построение  кучи.   void  BuildHeap(  CArray&  arr,  int  i  )   {          for(  int  i  =  arr.Size()  /  2  –  1;  i  >=  0;  -­‐-­‐i  )  {                  Heapify(  arr,  i  );          }   }  
  • 46. СД «Двоичная куча» Утверждение. Время работы BuildHeap = O(n). Доказательство. Время работы Heapify для работы с узлом, который находится на высоте h, равно O(h). На любом уровне, находящемся на высоте h, содержится не более ⌈​ 𝑛∕​2↑ℎ+1  ⌉ узлов. Общее время работы: 𝑇(𝑛)=∑ℎ=0↑​log⁠ 𝑛 ▒⌈​ 𝑛/​2↑ℎ+1  ⌉𝑂(ℎ) = 𝑂(𝑛∑ℎ=0↑​log⁠ 𝑛 ▒​ℎ/​ 2↑ℎ   ). Воспользуемся формулой ∑ℎ=0↑∞▒​ℎ/​2↑ℎ   =​​1∕2 /​(1−​ 1∕2 )↑2  =2. Таким образом, 𝑇(𝑛)= 𝑂(𝑛∑ℎ=0↑∞▒​ℎ/​2↑ℎ   )= 𝑂(𝑛). 46
  • 47. СД «Двоичная куча» 47 1.  Добавим элемент в конец кучи. 2.  Восстановим свойство упорядоченности, проталкивая элемент наверх. Если элемент больше отца, мы меняем местами его с отцом. Если после этого отец больше деда, мы меняем местами отца с дедом, и так далее. Время работы – 𝑂(​log⁠ 𝑛 ). Добавление элемента
  • 48. СД «Двоичная куча» 48 //  Добавление  элемента.   void  Add(  CArray&  arr,  int  element  )   {          arr.Add(  element  );          int  i  =  arr.Size()  –  1;          while(  i  >  0  )  {                  int  parent  =  (  i  –  1  )  /  2;                  if(  arr[i]  <=  arr[parent]  )                          return;                  std::swap(  arr[i],  arr[parent]  );                  i  =  parent;          }   }  
  • 49. СД «Двоичная куча» 49 Максимальный элемент располагается в корне. Для его извлечения выполним следующие действия: 1.  Сохраним значение корневого элемента для возврата. 2.  Скопируем последний элемент в корне, удалим последний элемент. 3.  Вызываем Heapify для корня. 4.  Возвращаем сохраненный корневой элемент. Время работы – 𝑂(​log⁠ 𝑛 ). Извлечение максимального элемента
  • 50. СД «Двоичная куча» 50 //  Извлечение  максимального  элемента.   int  ExtractMax(  CArray&  arr  )   {          assert(  !arr.IsEmpty()  );          //  Запоминаем  значение  корня.          int  result  =  arr[0];          //  Переносим  последний  элемент  в  корень.          arr[0]  =  arr.Last();          arr.DeleteLast();          //  Вызываем  Heapify  для  корня.          if(  !arr.IsEmpty()  )  {                  Heapify(  arr,  0  );          }          return  result;   }  
  • 51. АТД «Очередь с приоритетом» Определение. Очередь с приоритетом – абстрактный тип данных, поддерживающий три операции: 1.  InsertWithPriority – добавить в очередь элемент с нaзначенным приоритетом. 2.  GetNext – извлечь из очереди и вернуть элемент с наивысшим приоритетом. Другие названия: «PopElement», «GetMaximum». 3.  PeekAtNext (необязательная операция): просмотреть элемент с наивысшим приоритетом без извлечения. 51
  • 52. АТД «Очередь с приоритетом» АТД «Очередь с приоритетом» может быть реализован с помощью СД «Двоичная куча». §  Операции InsertWithPriority соответствует Add. Время работы – 𝑂(​log⁠ 𝑛 ). §  Операции GetNext соответствует ExtractMax. Время работы – 𝑂(​log⁠ 𝑛 ). §  Операции PeekAtNext соответствует возврат arr[0]. Время работы – 𝑂(1). 52
  • 53. Итог Было рассказано на лекции: §  Структура данных «Динамический массив». Амортизированное время добавления элемента. §  Связные списки. §  Абстрактные типы данных «Стек», «Очередь», «Дек». Способы реализации. §  Структура данных «Двоичная куча». §  Абстрактный тип данных «Очередь с приоритетом». 53