АкушерствоАнатомияАнестезиологияВакцинопрофилактикаВалеологияВетеринарияГигиенаЗаболеванияИммунологияКардиологияНеврологияНефрологияОнкологияОториноларингологияОфтальмологияПаразитологияПедиатрияПервая помощьПсихиатрияПульмонологияРеанимацияРевматологияСтоматологияТерапияТоксикологияТравматологияУрологияФармакологияФармацевтикаФизиотерапияФтизиатрияХирургияЭндокринологияЭпидемиология

Множество

Прочитайте:
  1. В общем случае множество U можно представить в виде
  2. Существует множество отдельных нозологических единиц ИДС.

 

Множество – это совокупность элементов с обычными теоретико-множественными операциями: проверка вхождения элемента (принадлежности) данному множеству, пересечения, объединения, вычитания множеств и т. п.

Рассмотрим два основных подхода к представлению множеств: в виде таблицы и в виде характеристического вектора.

1. Таблица содержит описание каждого элемента, принадлежащего множеству. Операции над элементом и множеством - проверка принадлежности элемента, его присоединение или удаление из множества - соответствуют поиску, включению и исключению в таблице. Объединение, пересечение и вычитание множеств удобно реализовать слиянием упорядоченных таблиц.

2. Для хранения подмножеств некоторого базового множества удобен характеристический вектор - битовый вектор длиной N, i-й разряд которого соответствует i-му элементу базового множества и равен 1, если этот элемент принадлежит хранимому (под)множеству, и 0, если не принадлежит. Характеристический вектор позволяет представлять 2N возможных подмножеств базового множества c мощностью (количеством элементов) N.

Операции над множествами реализуются в этом случае очень быстрыми поразрядными (битовыми) операциями: объединение - дизъюнкцией (ИЛИ, в языке Си обозначается одной вертикальной чертой |), пересечение - конъюнкцией (И, в Си &), вычитание из базового множества (дополнение) - инверсией (отрицанием, в Си ~). Эти операции во многих случаях выполняются одной машинной командой. Таким же образом в множество легко включать и исключать элементы, представляя их как одноэлементные множества.

Характеристический вектор эффективен для "плотных" подмножеств базового множества при наличии простого соотношения между элементом и его номером i. Этот метод обычно применяется для реализации множеств, имеющихся в языке Pascal. Их мощность не превышает 256.

Пример 3.24. Дни недели. Для хранения подмножества дней недели достаточно одного байта: Пусть, например, бит с номером 0 представляет понедельник, бит 1 - вторник,..., бит 6 - воскресенье. Бит 7 остается неиспользованным и будет равен нулю. На рис. 3.16 показаны несколько примеров представления множеств дней недели битовым вектором и операций над ними. Эти множества реализуются следующим фрагментом С-программы.

typedef char dni; /* Тип - множество дней недели: 0..6 */

dni rab_dni = 0x1F, /* Рабочие дни - биты: 0001 1111 */

/* Номера дней (битов) 7654 3210 */

vyh_dni = 0x60, /* Выходные дни - биты: 0110 0000 */

zan, dezh, svob; /* Дни занятий, дежурств, свободные */

...

svob = ~(zan | dezh) & 0x7F; /* Свободные дни */

if (svob & vih_dni) ... /* Есть свободные выходные дни? */

 

  Дни недели: -всп чсвп
  Номера битов: 7654 3210
Дни занятий: {пн,ср,пт} zan 0001 0101
Дни дежурств: {ср,сб} dezh 0010 0100
Занятые дни zan | dezh 0011 0101
Незанятые дни ~(zan | dezh) 1100 1010
Маска использованных битов (в 16-й системе) 0x7F 0111 1111
Свободные дни: svob = ~(zan | dezh)&0x7F 0100 1010
Выходные дни: vyh_dni = 0x60 0110 0000
Есть свободные выходные дни (svob & vyh_dni) ¹ 0 0100 0000 ¹ 0
  Рис. 3.16. Множества дней недели

 

Пример 3.25. Простые числа < 1000000. Задача: проверить, является ли заданное целое X < 1000000 простым числом (делится только на 1 и на себя).

Решение 1. Деление на все нечетные числа, не превышающие корень квадратный из X (до 500 делений - медленно!)

Решение 2. Хранить таблицу простых чисел меньших 1000000 в виде упорядоченного по возрастанию вектора из 78498 чисел по 4 байта, всего 313992 байта. Поиск требует до log 2 78498 = 17 делений пополам. Много памяти!

Решение 3. Хранить таблицу простых чисел меньших 1000000 как подмножество нечетных чисел в виде характеристического вектора из 500000 бит = 62500 байт (в 5 раз меньше, чем в решении 2!).

Используем массив tpr из 31250 двухбайтовых чисел без знака типа unsigned. Тогда j-й бит i-го элемента массива tpr соответствует нечетному числу X = 2*(16*i+j)+3.

Обозначим: y = 16*i+j. Тогда при данном X найдем:

y = (X-3)/2, i = y/16, j = y%16.

Отсюда получается подпрограмма проверки простоты числа:

/* Таблица: j-й бит tpr[i] = Число 2*(16*i+j)+3 - простое */

unsigned tpr[31250] =

{ 0x65B7, /* 0 1 1 0 0 1 0 1 1 0 1 1 0 1 1 1 */

/* 33 31 29 27 25 23 21 19 17 15 13 11 9 7 5 3 */

...

};

/* Таблица степеней 2: st2[i] = 2**i (I = 0..15) */

unsigned st2[16] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512,1024,

2048, 4096, 8192, 16384, 32768};

...

/* Функция: X - простое число (X < 1000000) */

int prostoe_chislo (long X) {

if (X == 1) return 0; /* 1 не считают простым числом */

if (X%2) { X = (X - 3) / 2; return tpr[X / 16] & st2[X % 16]; }

return 0;

}

Быстрее и проще заменить в операторе return деление и степень сдвигом: return tpr[X >> 4] & (1 << (X % 16)).

Тогда не нужна таблица степеней 2.

 

Еще быстрее вычислять остаток от деления на 16 выделением четырех младших бит: X%16 заменить на X & 0xF.

 

Решение 4. Компромисс между решениями 1 и 3: для проверки простоты выполнять деление X на простые числа, не превышающие квадратного корня из X, который меньше 1000. Для этого хранить таблицу из 168 двухбайтовых простых чисел, меньших 1000. Требует до 168 делений.

 


Дата добавления: 2015-09-27 | Просмотры: 429 | Нарушение авторских прав







При использовании материала ссылка на сайт medlec.org обязательна! (0.004 сек.)