Advertisement
Tochoz

bitmask

May 10th, 2024
480
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 17.43 KB | None | 0 0
  1. package bitmask;
  2.  
  3. public class Set {
  4.     private int start, end;
  5.     private int[] bits;
  6.  
  7.     public Set(int start, int end){
  8.         // если start > end то переставить местами
  9.         if (start > end){
  10.             this.end = start;
  11.             this.start = end;
  12.         } else {
  13.             this.start = start;
  14.             this.end = end;
  15.         }
  16.  
  17.         // определение числа в котором будет находиться первый и последний бит
  18.         int startEl = getElementNum(this.start), endEl = getElementNum(this.end);
  19.  
  20.         // определение длины отрезка от startEl до endEl и выделение такого количества чисел в массиве (endEl-startEl+1)
  21.         bits = new int[endEl-startEl+1];
  22.     }
  23.  
  24.     public Set(Set B){
  25.         start = B.start;
  26.         end = B.end;
  27.         bits = getarraycopy(B.bits);
  28.     }
  29.     // Закрытый конструктор выделяет память под массив и копирует элементы полученного множества
  30.     private Set(int start, int end, Set set){ // todo добавил
  31.         this.start = start;
  32.         this.end = end;
  33.  
  34.         // Выделение памяти под массив чисел
  35.         int startEl = getElementNum(this.start), endEl = getElementNum(this.end);
  36.         bits = new int[endEl-startEl+1];
  37.  
  38.         // смещение элемента где в текущем массиве начинается переданное множество
  39.         int offset = getElementNum(set.start) - startEl;
  40.  
  41.         // копирование значений из array со сдвигом на offset
  42.         for (int i=0; i<set.bits.length; i++)
  43.             bits[i+offset] = set.bits[i];
  44.     }
  45.  
  46.     private static int[] getarraycopy(int[] a){ //Метод возвращает копию массива
  47.         int[] out = new int[a.length];
  48.  
  49.         for (int i=0; i<a.length; i++)
  50.             out[i] = a[i];
  51.  
  52.         return out;
  53.     }
  54.  
  55.     private int getElementNum(int x){ // определение номера битового поля в котором будет находиться бит числа х (-64; -33) -> -2 (-32; -1
  56.         if (x>=0) return x/32; //т.к. в каждом числе 32 бита
  57.         return -((-x-1)/32)-1; // Если отрицательный то смещается на 1 в большую сторону
  58.     }
  59.  
  60.     public int getInMaskPos(int x){
  61.         return (x<0? 32-((-x-1)%32)-1: x%32);
  62.     }
  63.  
  64.     private boolean isInSet(int x){ // проверка находится ли бит во множестве
  65.         // вычисления номера первого числа в массиве getElementNum(start)
  66.         // вычисление индекса числа в массиве где должен находиться х getElementNum(x) - getElementNum(start)
  67.         return isInMask(getElementNum(x) - getElementNum(start), getInMaskPos(x)); // отбрасываем минус у отрицательного числа
  68.     }
  69.  
  70.     private boolean isInMask(int ind, int x){ // метод проверяет является ли бит на х месте единицей в элементе ind массива
  71.         // побитовое и числа из массива с 1 << (31-x%32) смещаем 1 на n=x%32 бит справа
  72.         return (bits[ind] & (1 << (31-x))) != 0;
  73.         // если число не ноль то x есть в множестве.
  74.     }
  75.  
  76.     public boolean isCrossing(Set B){ // Доп метод проверяет пересекаются множества или нет
  77.         if (start > B.end || B.start > end) // случай когда она не пересекаются по границам они либо пустые, тогда не пересекаются либо не пустые и тогда не пересекаются
  78.             return false;
  79.  
  80.         if (B == this) {
  81.             return true; // Если ссылки одинаковые то пересекаются
  82.         }
  83.  
  84.         //Нахождение позиций начала и конца каждого из множеств
  85.         int AStartEl = getElementNum(start), BStartEl = getElementNum(B.start), AEndEl = getElementNum(end), BEndEl = getElementNum(B.end);
  86.  
  87.         // определение числа в котором будет находиться первый и последний бит
  88.         int startP = (AStartEl > BStartEl)? AStartEl: BStartEl; // Максимальная позиция начала
  89.         int endP = (AEndEl < BEndEl)? AEndEl: BEndEl; // Минимальная позиция конца
  90.  
  91.         for (int p = startP; p<=endP; p++) // Проход по числам пересечения и их побитовое И
  92.             if ((bits[p - AStartEl] & B.bits[p - BStartEl]) != 0) return true; // если побитовое И не нулевое то есть перечесение вернуть истину
  93.  
  94.         return false; // если дошли до конца вернуть ложь
  95.     }
  96.  
  97.     private Set union(Set B){ // Закрытый метод выполняет объединение todo сделать на копировании первого и добавление второго
  98.  
  99.         int startRES = (start < B.start)? start: B.start; // Старт результирующего множества
  100.         int endRES = (end > B.end)? end: B.end; // Конец результирующего множества
  101.  
  102.         // Создание копии первого множества с объединёнными границами и копией значений текущего массива со сдвигом
  103.         Set RES = new Set(startRES, endRES, this);
  104.  
  105.         //Нахождение позиций начала и конца второго множества
  106.         int BStartEl = getElementNum(B.start), BEndEl = getElementNum(B.end);
  107.         int RESStartEl = getElementNum(startRES); // Позиция начала результирующего множества
  108.  
  109.         // Добавление в множество элементов второго множества на нужные места
  110.         for (int el = BStartEl; el <= BEndEl; el++)
  111.             RES.bits[el - RESStartEl] |= B.bits[el - BStartEl];
  112.  
  113.         return RES;
  114.     }
  115.  
  116.     public Set UNION(Set B){
  117.         // если один из них пустой или указатели совпадают то вернуть копию текущего или другого
  118.         if (B == null || B == this) return new Set(this);
  119.         // вызываем union
  120.         return union(B);
  121.     }
  122.  
  123.     public Set INTERSECTION(Set B) {
  124.         if (B == this) return new Set(this); // Если это одни и те же указатели
  125.         //проверка пересекаются ли множества если нет или B пустое вернуть пустую копию текущего множества
  126.         if (B == null || !isCrossing(B)) return new Set(start, end);
  127.         //A и B Ссылки на множества, если надо, переставить так чтобы A.start <= B.start
  128.         Set A = this;
  129.         if (A.start>B.start){ // если второе начинается раньше, перетсавляем
  130.             A=B; B=this;
  131.         }
  132.         //создание нового множества с пересечением границ RES = new Set(...)
  133.         Set RES = new Set(B.start, A.end);
  134.  
  135.         //Нахождение позиций нулей и концов каждого из множеств --> AStartEl BStartEl AEndEl BEndEl
  136.         int AStartEl = getElementNum(A.start), BStartEl = getElementNum(B.start), AEndEl = getElementNum(A.end), BEndEl = getElementNum(B.end);
  137.         int endP = (AEndEl < BEndEl)? AEndEl: BEndEl; // Минимальная позиция конца
  138.  
  139.         // Применяем побитовое и для чисел на позициях начиная с BStartEl заканчивая BEndEl
  140.         for (int pos = BStartEl; pos <= endP; pos++)
  141.             RES.bits[pos - BStartEl] = A.bits[pos-AStartEl] & B.bits[pos-BStartEl];
  142.  
  143.         return RES;
  144.     }
  145.  
  146.     public Set DIFFERENCE(Set B){
  147.         if (B == this) return new Set(start, end); // Если это одни и те же указатели то будет пустое множество с теми же границами
  148.         //Если B пустое вернуть копию текущего множества
  149.         if (B == null) return new Set(this);
  150.  
  151.         Set RES = new Set(this); // Формируем множество на основе текущего
  152.  
  153.         //Нахождение позиций начала и конца каждого из множеств
  154.         int AStartEl = getElementNum(start), BStartEl = getElementNum(B.start), AEndEl = getElementNum(end), BEndEl = getElementNum(B.end);
  155.  
  156.         // определение позиций начала и конца пересечений
  157.         int startP = (AStartEl > BStartEl)? AStartEl: BStartEl; // Максимальная позиция начала
  158.         int endP = (AEndEl < BEndEl)? AEndEl: BEndEl; // Минимальная позиция конца
  159.  
  160.  
  161.         for (int p = startP; p<=endP; p++) // Проход по числам пересечения и их побитовое вычитание Если границы не пересекаются то ничего не будет
  162.             RES.bits[p - AStartEl] &= ~B.bits[p - BStartEl];
  163.  
  164.         return RES;
  165.     }
  166.  
  167.     public Set MERGE(Set B){
  168.         // если один из них пустой или указатели совпадают то вернуть копию текущего или другого
  169.         if (B == null || B == this) return new Set(this);
  170.         // вызываем union
  171.         return union(B);
  172.     }
  173.  
  174.     public boolean MEMBER(int x){ // Метод проверяет наличие
  175.         // если х не находится в области определения вернуть ложь
  176.         if (start>x || x>end) return false;
  177.         // вызвать isInSet
  178.         return isInSet(x);
  179.     }
  180.  
  181.     public void MAKENULL(){
  182.         // проход по массиву и зануление всех чисел
  183.         for (int i=0; i<bits.length; i++)
  184.             bits[i]=0;
  185.     }
  186.  
  187.     public void INSERT(int x){
  188.         //проверка что х в границах
  189.         if (start>x || x>end) return;
  190.         //Вычислить offset номер первого элемента массива вычислить в каком числе будет х
  191.         int AStartEl = getElementNum(start), xEl = getElementNum(x);
  192.         //побитовое или элемента массива[xEl-AStartEl] и 1 << (31-x%32)
  193.         bits[xEl-AStartEl] |= 1 << (31-x%32);
  194.  
  195.     }
  196.  
  197.     public void DELETE(int x){
  198.         //проверка что х в границах
  199.         if (start>x || x>end) return;
  200.         //Вычислить offset номер первого элемента массива вычислить в каком числе будет х
  201.         int AStartEl = getElementNum(start), xEl = getElementNum(x);
  202.         //побитовое и элемента массива[xEl-AStartEl] c -(1 << (31-x%32))
  203.         bits[xEl-AStartEl] &= ~(1 << (31-x%32));
  204.     }
  205.  
  206.     public void ASSIGN(Set B){
  207.         // проверить ссылки различные
  208.         if (this == B) return;
  209.         // заменить границы
  210.         start = B.start; end = B.end;
  211.         // если массивы одной длинны то просто скопировать
  212.         if (bits.length == B.bits.length)
  213.             for (int i=0; i<bits.length; i++)
  214.                 bits[i] = B.bits[i];
  215.         else
  216.             // иначе создать новый массив
  217.             bits = getarraycopy(B.bits);
  218.     }
  219.  
  220.     public int MIN(){ // возвращает минимальный элемент содержащийся во множестве
  221.         // пока элемент массива нулевой, дальше
  222.         int i=0;
  223.         while (i < bits.length && bits[i] == 0)
  224.             i++;
  225.  
  226.         // Если прошли весь массив то в массиве нет элементов и выводим end+1
  227.         if (i == bits.length) throw new SetException("Множество пустое, нет минимального элемента");
  228.  
  229.         int x=(i==0? getInMaskPos(start): 0);// если первый элемент ненулевой то начинаем проверку с start%32 бита
  230.         int lastbit = (i+1==bits.length? getInMaskPos(end): 31); // если в последнем числе массива то идём до end
  231.  
  232.  
  233.         // идём по битам пока они нулевые (число при этом точно не нулевое)
  234.         while (!isInMask(i,x))
  235.             x++;
  236.  
  237.  
  238.         return (getElementNum(start)+i)*32+x; // вернуть хранимое число
  239.     }
  240.     public int MAX() { // аналогично MIN но с обратной стороны
  241.         // пока элемент массива нулевой, дальше
  242.         int i=bits.length-1;
  243.         while (i >= 0 && bits[i] == 0)
  244.             i--;
  245.  
  246.         // Если прошли весь массив то в массиве нет элементов и выводим start-1
  247.         if (i == -1) throw new SetException("Множество пустое, нет максимального элемента");
  248.  
  249.         int firstbit=(i==0? getInMaskPos(start): 0);// если первый элемент ненулевой то начинаем проверку до start%32 бита
  250.         int x = (i+1==bits.length? getInMaskPos(end): 31); // если в последнем числе массива то идём до end
  251.  
  252.  
  253.         // идём по битам пока не дошли до конца и они нулевые
  254.         while (x >= firstbit && !isInMask(i,x))
  255.             x--;
  256.  
  257.         return (getElementNum(start)+i)*32+x; // вернуть хранимое число
  258.     }
  259.  
  260.     public boolean EQUAL(Set B) {// Если границы разные но элементы совпадают то всё равно true
  261.         if (this == B) return true; // Если ссылка на одно и то же множество
  262.  
  263.         //A и B Ссылки на множества, если надо, переставить так чтобы A.start <= B.start
  264.         Set A = this;
  265.         if (A.start>B.start){
  266.             A=B; B=this;
  267.         }
  268.  
  269.         //Нахождение позиций начала и конца каждого из множеств
  270.         int AStartEl = getElementNum(A.start), BStartEl = getElementNum(B.start), AEndEl = getElementNum(A.end), BEndEl = getElementNum(B.end);
  271.         int Aind = AStartEl, Bind = BStartEl; //индексы для прохода массивах множеств А и В
  272.  
  273.         //1) Все ли элементы до пересечения нулевые
  274.         while (Aind < AEndEl && Aind != Bind)
  275.             if (bits[Aind++ - AStartEl] != 0)
  276.                 return false;
  277.  
  278.         //2) Проверка все ли элементы пересечения совпадают, если нашли несовпадение false
  279.         if (Aind == Bind) // Есть пересечение
  280.             while (Aind < AEndEl && Bind < BEndEl) // Пока один из массивов не закончится
  281.                 if (A.bits[Aind++ - AStartEl] != B.bits[Bind++ - BStartEl])
  282.                     return false;
  283.  
  284.         //3) Проверка оставшегося хвоста на пустоту
  285.         while (Aind <= AEndEl)//то конец первого множества остался
  286.             if (bits[Aind++ - AStartEl] != 0)
  287.                 return false;
  288.         while (Bind <= BEndEl) // конец второго множества остался
  289.             if (bits[Bind++ - BStartEl] != 0)
  290.                 return false;
  291.  
  292.         return true;
  293.  
  294.     }
  295.     public Set FIND(Set B, int x){ // ВСЁ НОРМАЛЬНО ТУТ
  296.         // Проверяем на каждом множестве если оно содержит х
  297.         if (start<x && x<end && isInSet(x))
  298.             return this;
  299.         else if (B.start<x && x<B.end && B.isInSet(x))
  300.             return B;
  301.  
  302.         return null; // Если ни в одном множестве нет этого элемента
  303.  
  304.     }
  305.  
  306.     public void PRINT(){
  307.  
  308.         for (int i=start; i<=end; i++) // Проход по всем возможным элементам множестве с проверкой есть ли они в нём
  309.             if (isInSet(i)) System.out.printf("%d ", i);
  310.         System.out.println();
  311.     }
  312.  
  313.     public void DEBUG_PRINT(){
  314.         StringBuilder out = new StringBuilder(bits.length*33);
  315.         for (int i=0; i< bits.length; i++) {
  316.  
  317.             for (int j=0; j<32; j++) {
  318.                 if ((bits[i] & 1<<(31-j)) == 0)
  319.                     out.append('0');
  320.                 else
  321.                     out.append('1');
  322.  
  323.             }
  324.             out.append(' ');
  325.         }
  326.         System.out.println(out);
  327.     }
  328.  
  329. }
  330.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement