e-olymp 6125. Простая очередь

Задача

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

  • push n — Добавить в очередь число n (значение n задается после команды). Программа должна вывести ok.
  • pop — Удалить из очереди первый элемент. Программа должна вывести его значение.
  • front — Программа должна вывести значение первого элемента, не удаляя его из очереди.
  • size — Программа должна вывести количество элементов в очереди.
  • clear — Программа должна очистить очередь и вывести ok.
  • exit — Программа должна вывести bye и завершить работу.

Гарантируется, что набор входных команд удовлетворяет следующим требованиям: максимальное количество элементов в очереди в любой момент не превосходит 100, все команды pop и front корректны, то есть при их исполнении в очереди содержится хотя бы один элемент.

Данную задачу также можно найти здесь.

Входные данные

Описаны в условии. Смотрите также тесты, расположенные ниже.

Выходные данные

Описаны в условии. Смотрите также тесты, расположенные ниже.

Тесты

Входные данные Выходные данные
1 push 123
size
push -5
pop
exit
ok
1
ok
123
bye
2 push 1
push 2
front
push 42
pop
exit
ok
ok
1
ok
1
bye
3 push 1
push 2
pop
pop
size
exit
ok
ok
1
2
0
bye

Код

Реализуем абстрактный тип данных очередь, который отвечает принципу FIFO («первый вошёл – первый вышел») с помощью массива. Очередь имеет начало и конец, на которые указывают соответственно start и finish. Изначально очередь является пустой, поэтому start = 0, finish = 0. При добавлении нового элемента в очередь записываем его в конец. finish при этом увеличиваем на единицу. Извлекаемый же элемент берём в начале очереди, после чего start++. Если необходимо получить значение начала очереди, не извлекая его, воспользуемся функцией front(), возвращающей значение первого элемента. Для получения размера очереди используем функцию size(), которая возвращает разницу между концом и началом очереди. Если очередь нужно очистить, то приравниваем finish и start к нулю.

Код на сайте ideone.com находится здесь.

Timus №2002

Условие и начальные данные можно посмотреть по ссылке.

Тест:

исходные данные результат
6
register alena 223344 success: new user added
login alena 223 fail: incorrect password
login alena 223344 success: user logged in
login john 454545 fail: no such user
logout alena success: user logged out
logout alena fail: already logged out

Решение:

Для решения этой задачи я использовала два ассоциативных массива. Первый (usersAndPasswords) хранит в качестве ключа имя зарегистрированного пользователя, а в качестве значения — пароль этого пользователя; второй (loggedInUsers) хранит вошедших на форум пользователей, а в качестве значения всегда единица, потому что мы никак не используем значение, нам важно только есть ли имя пользователя в этом массиве или нет.

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

Ссылка на решение на ideone.

Ссылка на засчитанное решение на http://acm.timus.ru/.

Timus 2002 by Tolia

Для решения использовалось AVL-дерево выложенное тут.

Алгоритм решения задачи с соответствием с условием задачи.

 

Ссылка на решение.

BST – Двоичные деревья поиска

Задача

Разработать класс, реализующий функциональность дерева двоичного поиска.

Ссылка на условие http://java.mazurok.com/word-of-week/bst

Тесты

input output
put S 11.11 Ok
put E 22.22 Ok
put A 33.33 Ok
put R 44.44 Ok
put H 55.55 Ok
put C 66.66 Ok
put X 77.77 Ok
put M 88.88 Ok
size 8
min (A->33.33)/2
max (X->77.77)/1
print L0: (S->11.11)/8
.L1: (E->22.22)/6
..L2: (A->33.33)/2
…L3: (C->66.66)/1
..L2: (R->44.44)/3
…L3: (H->55.55)/2
….L4: (M->88.88)/1
.L1: (X->77.77)/1
delete E Ok
size 7
min (A->33.33)/2
max (X->77.77)/1
print L0: (S->11.11)/7
.L1: (H->55.55)/5
..L2: (A->33.33)/2
…L3: (C->66.66)/1
..L2: (R->44.44)/2
…L3: (M->88.88)/1
.L1: (X->77.77)/1
exit N/A

Критерий тестирования

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

Формат вывода:

Команды min и max выводят одиночный узел в следующем формате: (ключ->значение)/кол-во узлов

Команда print выводит дерево по уровням, каждая строчка имеет следующий формат: уровень: (ключ->значение)/кол-во узлов

Структура программы

Код программы состоит из следующих элементов, объединенных в пакет odessa.uni.imem.maxim:

  1. Класс CountingBST, реализующий функциональность дерева двоичного поиска с подсчетом количества узлов в дереве
  2. Класс CountingBSTTestApp, реализующий тестовое приложение

Класс CountingBST

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

  1. put — помещает ключ и значение в дерево
  2. get — извлекает значение по клчу
  3. size — возвращает количество узлов дерева
  4. min — находит узел с минимальным ключом
  5. max — находит узел с максимальным ключом
  6. delete — удаление по Хиббарду ( Coursera presentation )
  7. print — печать дерева

Помимо основных полей, необходимых для BST, узел содержит поле count, в котором содержится количество все узлов поддерева, корнем которого является данный узел, включая сам узел.

Класс CountingBSTTestApp

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

Ссылка на Ideone: https://ideone.com/b0xrPX

 

acm.timus.ru №2002. Тестовое задание

Автор задачи: Кирилл Бороздин
Источник задачи: Уральская региональная командная олимпиада по программированию 2013

Ограничения:

Время: 0.5 секунды
Память 64 Мб

Условие

Это было обычное хмурое октябрьское утро. Небо было затянуто тяжёлыми серыми тучами, накрапывал дождь. Капли падали на стёкла автомобилей, били в окна домов. Илья сидел за компьютером и угрюмо взирал на унылый пейзаж за окном. Внезапно его взгляд привлекла надпись, появившаяся в правом нижнем углу экрана: «You have 1 unread email message(s)». Заранее приготовившись удалить бесполезный спам, Илья открыл письмо. Однако оно оказалось куда интереснее…
Вас приветствует отдел по работе с персоналом компании «Рутнок БКС»!
Мы рассмотрели вашу заявку на вакансию разработчика программного обеспечения и были заинтересованы вашей кандидатурой. Для оценки ваших профессиональных навыков мы предлагаем вам выполнить несложное тестовое задание: необходимо реализовать систему регистрации для форума. Она должна поддерживать три операции:
  1. «register username password» — зарегистрировать нового пользователя с именем «username» и установить для него пароль «password». Если такой пользователь уже есть в базе данных, необходимо выдать ошибку «fail: user already exists». Иначе нужно вывести сообщение «success: new user added».
  2. «login username password» — войти в систему от имени пользователя «username» с паролем «password». Если такого пользователя не существует в базе данных, необходимо выдать «fail: no such user». Иначе, если был введен неправильный пароль, нужно выдать «fail: incorrect password». Иначе, если пользователь уже находится в системе в данный момент, необходимо вывести «fail: already logged in». Иначе нужно вывести сообщение «success: user logged in».
  3. «logout username» — выйти из системы пользователем «username». Если такого пользователя не существует, необходимо вывести «fail: no such user». Иначе, если пользователь не находится в системе в данный момент, следует выдать «fail: already logged out». Иначе необходимо выдать сообщение «success: user logged out».
Пользуйтесь этим письмом как формальным описанием алгоритма и строго соблюдайте порядок обработки ошибок. Желаем вам удачи!
И вот Илья, откинув все дела, уже решает тестовое задание. Попробуйте и вы выполнить его!

Исходные данные

В первой строке дано целое число [latex]n[/latex] — количество операций [latex]1\leq n\leq 100[/latex]. В каждой из следующих [latex]n[/latex] строк содержится один запрос в соответствии с форматом, описанным выше. В качестве «username» и «password» могут выступать любые непустые строки длиной до 30 символов включительно. Строки могут состоять только из символов с кодами от 33 до 126.

Результат

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

Пример

Исходные данные Результат
6register vasya 12345

login vasya 1234

login vasya 12345

login anakin C-3PO

logout vasya

logout vasya

success: new user addedfail: incorrect password

success: user logged in

fail: no such user

success: user logged out

fail: already logged out

Код

Данная программа представляет собой типичный пример использования таблицы символов, согласно терминологии Coursera. Для доступа к учетным записям используется интерфейс Map, а для реализации самой базы данных учетных записей — объект типа TreeMap. Учетная запись пользователей реализована в виде одного элемента типа Map.entry, где имя пользователя — это ключ, а атрибуты учетной записи — пароль и флаг подключен/отключен — реализованы в виде отдельной структуры AccountInfo, которая является значением этого ключа.

Время работы Выделено памяти
0.124 1 928 КБ
 Ссылка на Ideone: https://ideone.com/3Y2W4z

Binary Heap (двоичная куча)

В данном отчёте я напишу о структуре данных под названием куча (Heap), а точнее — о её разновидности.

Двоичная куча

Двоичная куча — структура данных, двоичное дерево, для которого выполнены три условия:

  • Значение в любой вершине не меньше чем значение в потомках
  • Расстояние до корня отличается не более чем на один уровень
  • Заполняется слева на право

Зафиксируем операции, которые будем проводить над кучей:

  • Достать максимальный элемент из кучи, не удаляя его
  • Добавить элемент в кучу
  • Создать кучу
  • Отсортировать массив путём превращения его в кучу, а кучи — в отсортированный массив
  • Узнать размер кучи
  • Удалить максимальный элемент из кучи

Описание методов

1. Восстановление свойства кучи

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

Сложность: [latex]O(\log(n))[/latex]

2. Возврат максимального элемента

Возвратить содержимое самой верхней вершины.

Сложность: [latex]O(1)[/latex]

3. Удаление максимального элемента

Меняются местами первая и последняя вершины, после чего последняя вершина запоминается и удаляется, а новая первая вершина проталкивается в кучу, согласно её свойствам.

Сложность: [latex]O(\log(n))[/latex]

4. Пирамидальная сортировка

Достаточно заметить, что в самую первую вершину кучи всегда (по крайней мере, по введённым свойствам) встаёт максимальный элемент. Если каждый раз удалять максимальный элемент — получим отсортированный массив.

Сложность: [latex]O(n\log(n))[/latex]

О реализации

Реализуется структура данных с абстрактным типом данных.  Для хранения вершин будем использовать ArrayList. Для каждой вершины под номером [latex]i[/latex] её левый сын хранится в [latex]2*i+1[/latex] вершине, а правый — в [latex]2*i+2[/latex] вершине.

Класс содержит следующие методы:

  • Heap() — конструктор
  • shiftUp() — восходящее восстановление свойства кучи
  • shiftDown() — нисходящее восстановление свойства кучи
  • insert() — добавление элемента в кучу
  • delete() — удаление первой вершины
  • size() — размер кучи
  • isEmpty() — проверка на пустоту
  • toString() — преобразование в строку
  • max() — максимальный элемент
  • print() — вывод кучи на экран

Код

 

Частотный словарь

Определение понятия «частотный словарь» можно посмотреть в Википедии.

Реализовывалось на своем АВЛ-дереве.

Сначала надо распарсить строку на слова, которые удовлетворяют условию задачи 1. Потому, надо с помощью структуры данных как map реализовать дерево, поддерживающее ключ -> значение структуру. АВЛ-дерево в каком-то роде схоже с map, так что можно использовать его. Правда оно не имплемирует ни одного интерфейса, которые имплемирует map. Разбив текст на слова и добавив их в дерево с количеством их вхождений мы можем вывести частоту каждого из них. Для хранения общего количества слов используется переменная внутри словаря. Библиотека имеет один метод для получения результата — это по заданному слову выдать частоту его вхождения. Если необходимо вывести все слова в словаре, то тогда можно расширить класс АВЛ-дерева.

#include <iostream>
using namespace std;int main() {for( int i = 0; i < 10; i++ )
{
if( i % 2 == 0 )
{
cout << “Even” << endl;
}
else
{
cout << “Odd” << endl;
}
}
return 0;
}%EOF%

 

0 3 0.1111111111111111
10 1 0.037037037037037035
2 1 0.037037037037037035
Even 1 0.037037037037037035
Odd 1 0.037037037037037035
cout 2 0.07407407407407407
else 1 0.037037037037037035
endl 2 0.07407407407407407
for 1 0.037037037037037035
i 4 0.14814814814814814
if 1 0.037037037037037035
include 1 0.037037037037037035
int 2 0.07407407407407407
iostream 1 0.037037037037037035
main 1 0.037037037037037035
namespace 1 0.037037037037037035
return 1 0.037037037037037035
std 1 0.037037037037037035
using 1 0.037037037037037035
aaa for bbb aaa for if
%EOF%
aaa 2 0.3333333333333333
bbb 1 0.16666666666666666
for 2 0.3333333333333333
if 1 0.16666666666666666

 

Ссылка на ideone.

Обратная польская запись

Что такое обратная польская запись можно прочитать в Википедии.

Использовался свой стек, выложенный ранее тут.

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

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

 

 

Ссылка на ideone.

Стек v.Java

        Stack test = new Stack(4);
        System.out.println(test.isEmpty());
        test.push(12);
        System.out.println(test.isEmpty());
        System.out.println(test.peek());
        test.push(13);
        test.push(14);
        test.push(15);
        test.push(16);
        test.push(17);
        test.push(‘(‘);
        System.out.println(test.size());
        System.out.println(test.peek().equals(‘(‘));
        test.pop();
        System.out.println(test.peek());
        test.pop();
        System.out.println(test.peek());
        test.pop();
        System.out.println(test.peek());
        test.pop();
        System.out.println(test.peek());
        test.pop();
        System.out.println(test.peek());
        System.out.println(test.isEmpty());
        test.pop();
        System.out.println(test.peek());
        test.pop();
        System.out.println(test.isEmpty());
true

false

12

7

true

17

16

15

14

13

false

12

true

Что такое стек прекрасно расскажет Википедия.

Реализация динамического стека. Есть приватная функция resize, которая меняет размер массива, выделяемого под стек. Массив копируется в новый с помощью Java’вского копирования массивов.

Есть тестовый вывод, для проверки корректности всех методов.

Ссылка на ideone.

АВЛ-дерево

Описание АВЛ-дерева вы можете прочитать в Википедии.

Здесь представлен код реализации рекурсивного АВЛ-дерева. Отличается от обычно бинарного дерева тем, что у узлов есть высота и показатель балансировки. Балансировка может меняться при добавлении или удалении, и восстанавливается с помощью малого левого(правого), или большого левого(правого) поворотов. Как это выглядит можно увидеть в той же Википедии.

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

Для возможности бегать по узлам дерева, есть приватные функция getHigherNode, getLowerNode. К которым есть доступ у узлов. К примеру мы в самой левой вершине дерева, либо мы лист, либо у нас есть правое поддерево. Если мы лист, то надо вернуть просто нашего предка. Если же есть правое поддерево. То надо вывести следующую вершину справа. Мы попали в эту вершину. Мы снова либо лист, либо есть правое поддерево, либо есть левое поддерево, либо сразу оба. Если мы лист, то нам надо подняться вверх по дереву, пока мы являемся правым сыном нашего предка, как только мы попадем в наш первоначальный самый маленький узел, мы перестаем быть правым сыном, значит нам пора остановиться, и вернуть отца самого маленького узла. Если же есть только правое поддерево(вернулись к моменту, где мы правый узел от самого маленького), то спускаемся снова вправо и имеем те же ситуации. Если же есть только левое поддерево, то заходим в него и действуем по тем же правилам. Если есть оба, то сначала пойдем в левое поддерево, после того, как мы там побываем и вернемся к узлу, нам надо будет продолжить обходить правое поддерево.

Попробуйте данный алгоритм действия, для этого дерева.

  • Определите следующий элемент для узла 0001.
  • Определите следующий элемент для узла 0003.
  • Определите следующий элемент для узла 0004.
  • Определите следующий элемент для узла 0005.
  • Определите следующий элемент для узла 0007, зная, что предок корня — это null.

Дерево

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

 

 

Ссылка на ideone.