Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ответы Тех.програм.docx
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
291.5 Кб
Скачать

Добавление новой строки в бор:

Пусть в начале добавления мы находимся в вершине с номером v  = 0. Разберем 2 случая:

  1.  Мы пытаемся добавить s[i] букву и находимся в вершине v, а так же tree[v].num[s[i] - 'a'] не равно -1. Из этого следует, что переход для данной вершины по нужной нам букве уже существует, и достаточно просто изменить   v = tree[v].num[s[i] - 'a'].

  1. Мы пытаемся добавить s[i] букву и находимся в вершине v, однако теперь tree[v].num[s[i] - 'a'] равно -1. Значит еще не существует вершины в которую нужно перейти, а следовательно нужно ее добавить -увеличим глобальный счетчик cc и запишем в tree[v].num[s[i] - 'a'] новое значение cc, а также изменимv = cc.

После добавления последнего символа строки нам нужно tree[v].term приравнять к 1 (сказать, что в данной вершине одно из слов, добавленных в бор, закончилось) - это нам понадобится в поиске.

Поиск строки в боре:

При поиске в боре мы, можно сказать, просто спускаемся пока это возможно и можно выделить 2 случая:

  1. Если в какой то момент мы находимся в вершине v и хотим перейти в след вершину по символу s[i] иtree[v].num[s[i] - 'a'] = -1, то просто прекращаем поиск и говорим, что такого слова в нашем дереве нет.

  1. Слово, которое мы ищем кончилось, и мы находимся в вершине vЕсли параметр term для данной вершины равен 1, то мы нашли слово, иначе нет.

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

Реализация:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

int cc = 0; // глобальны счетчик вершин

 

// добавление

int v = 0;

for (int i = 0; i < s.length(); i++){

    int t = s[i];

    if (tree[v].num[t] == -1){

        cc++;

        tree[v].num[t] = cc;

    }

    v = tree[v].num[t];

}

tree[v].term = 1;

 

// поиск

int v = 0;

for (int i = 0; i < s.length(); i++){

    int t = s[i];

    if (tree[v].num[t] == -1){

        printf("Такого слова нет");

        break;

    }

    v = tree[v].num[t];

}

if (tree[v].term)

    printf("Такое слово есть в словаре");

else

    printf("Такого слова нет в словаре!");

Методы хранения бора:

  1. Самый простой метод я уже описал, в нем для каждого состояния поиск нужного перехода осуществляется за O(1), однако мы используем довольно много лишней памяти, так как по сути всегда храним все возможные переходы.

  1. Если размер возможного алфавита довольно велик и просто нет возможности хранить массив num[] для каждой вершины, то можно данный массив заменить на map <char, int> num. Тогда мы избавимся от проблемы недостатка памяти, но так как поиск и добавление в map происходит за O(log), то асимптотика домножится на log.

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