Advertisement
Tochoz

linked

May 10th, 2024 (edited)
820
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 25.21 KB | None | 0 0
  1. package linkedlist;
  2.  
  3. public class Set {
  4.     private Item tail;
  5.     private int start, end;
  6.  
  7.     private class Item{ // Элемент списка
  8.         private int val; // Храним число множества
  9.         private Item next; // Указатель на следующий
  10.  
  11.         private Item(int val){
  12.             this.val = val;
  13.         }
  14.  
  15.         private Item(int val, Item next){
  16.             this.val = val;
  17.             this.next = next;
  18.         }
  19.  
  20.         private Item(Item B){
  21.             val = B.val;
  22.         }
  23.  
  24.         private void insertAfter(Item B){ // Метод вставляет элемент после текущего
  25.             B.next = next;
  26.             next = B;
  27.         }
  28.         private void deleteAfter(){
  29.             next = next.next;
  30.         }
  31.  
  32.         @Override
  33.         public String toString() {
  34.             return String.valueOf(val);
  35.         }
  36.     }
  37.  
  38.     public Set(int start, int end) {
  39.         this.start = start;
  40.         this.end = end;
  41.     }
  42.  
  43.     public Set(Set A){ // Копирующий конструктор
  44.         start = A.start;
  45.         end = A.end;
  46.         tail = copylist(A.tail);
  47.     }
  48.  
  49.     private Set(int start, int end, Set B){
  50.         this.start = start;
  51.         this.end = end;
  52.         this.tail = copylist(B.tail);
  53.     }
  54.  
  55.     // TODO в ASSIGN нужен
  56.     private Item copylist(Item reftail){ // Метод формирует копию входного кольцевого списка и возвращает хвост
  57.         Item newtail = new Item(reftail);
  58.         newtail.next = newtail;
  59.         // Проходом по кольцевому списку копируем
  60.         Item fir = newtail, sec = reftail.next; // Указатели по текущему и образцу
  61.         while (sec != reftail){ // Проход пока не дойдём до хвоста
  62.             fir.insertAfter(new Item(sec));
  63.             fir = fir.next;
  64.             sec = sec.next;
  65.         }
  66.         return newtail;
  67.     }
  68.  
  69.     private boolean isInSet(int x){ // Проверка находится ли элемент в множестве если оно состоит из более чем 1го элемента
  70.         if (tail.val == x) return true; // Если элемент в хвосте
  71.         Item prev = findPrevItem(tail, x); // Иначе ищем предыдущий
  72.  
  73.         // Если следующий элемент и есть искомое число то оно содержится в множестве
  74.         return prev.next.val == x;
  75.     }
  76.  
  77.     private Item findPrevItem(Item start, int x){ // Поиск элемента перед потенциальным местом x если он точно идёт до хвоста посик начинается с заданного элемента
  78.  
  79.         Item fir = start, sec = start.next; // Указатели по текущему и образцу
  80.         while (sec.val < x){ // Пока мы не дойдём до хвоста либо до элемента значение которого больше или равно искомому
  81.             if (sec == tail) break;
  82.             fir = fir.next;
  83.             sec = sec.next;
  84.         }
  85.  
  86.         return fir; // Если дошли до хвоста, то будет возвращён предпоследний
  87.     }
  88.  
  89.     public boolean isCrossing(Set B) { // Доп метод проверяет пересекаются множества или нет
  90.  
  91.         if (start > B.end || B.start > end) // случай когда она не пересекаются по границам они либо пустые, тогда не пересекаются либо не пустые и тогда не пересекаются
  92.             return false;
  93.  
  94.         if (B==this) // Если указатели совпадают то множества пересекаются
  95.             return true;
  96.  
  97.         Item a = tail.next, b = B.tail.next;// проход с головы каждого
  98.  
  99.         //пока не дойдём до конца хоть одного из списков если нашли совпадающие return true
  100.         while (a != tail && b != B.tail){
  101.             if (a.val == b.val) return true;
  102.             // Двигаем указатель с минимальным числом
  103.             if (a.val < b.val)
  104.                 a = a.next;
  105.             else
  106.                 b = b.next;
  107.         }
  108.  
  109.         if (a == tail){ // Если дошли до хвоста в первом списке
  110.             while (b != B.tail){ // Проверяем остаток второго списка на наличие в нём хвоста первого
  111.                 if (a.val == b.val) return true;
  112.                 b = b.next;
  113.             }
  114.             // Сравниваем хвосты
  115.             if (a.val == b.val) return true;
  116.         } else { // Дошли до хвоста во втором списке
  117.             while (a != tail){ // Проверяем остаток первого списка на наличие в нём хвоста второго
  118.                 if (a.val == b.val) return true;
  119.                 a = a.next;
  120.             }
  121.             // Сравниваем хвосты
  122.             if (a.val == b.val) return true;
  123.         }
  124.  
  125.         return false;
  126.  
  127.     }
  128.  
  129.     private Set union(Set B) { // TODO либо делать на основе копии либо разруливать первые
  130.         /*// Создать пустой список с временным хвостом
  131.         Item restail = new Item(0);
  132.         restail.next = restail;
  133.         Item r = restail; // указатель r по новому списку
  134.  
  135.         // Результирующие границы итогового множества
  136.         int resStart = (start < B.start ? start : B.start);
  137.         int resEnd = (end>B.end ? end : B.end);
  138.  
  139.         Item a = tail.next, b = B.tail.next; // Указатели для прохода по спискам
  140.         while (a != tail && b != B.tail) {
  141.             if (a.val == b.val) { // если значения совпадают, добавляем в результат и идём дальше в обоих
  142.                 r.insertAfter(new Item(a));
  143.                 a = a.next;
  144.                 b = b.next;
  145.             } else if (a.val < b.val) { // если в А число меньше, добавляем его в результат и идём дальше в первом
  146.                 r.insertAfter(new Item(a));
  147.                 a = a.next;
  148.             } else { // иначе добавляем второе и идём дальше во втором
  149.                 r.insertAfter(new Item(b));
  150.                 b = b.next;
  151.             }
  152.             r = r.next;
  153.         }
  154.  
  155.  
  156.         r = unionTail(r, a, b, B.tail); // Вызвать метод который объединит хвост и последний элемент, вернёт указатель в списке резулоьтате
  157.         r.next = restail.next; // Отвязываем временный хвост
  158.         return new Set(resStart, resEnd, r);
  159.         */
  160.  
  161.         // Результирующие границы итогового множества
  162.         int resStart = (start < B.start ? start : B.start);
  163.         int resEnd = (end>B.end ? end : B.end);
  164.  
  165.         Set RES = new Set(resStart, resEnd, this); // Копия первого множества с объединёнными границами
  166.  
  167.         Item b = B.tail.next, prev = RES.tail; // Указатели на элементы второго множества и поиска по результату
  168.         while (b!= B.tail && b.val < RES.tail.val){ // Проход по всем элементам множества B которые меньше хвоста A
  169.             prev = findPrevItem(prev, b.val); // Ищем элемент в результирующем множестве перед потенциальным местом вставки
  170.  
  171.             if (prev.next.val != b.val) // Если такого элемента нет, вставляем
  172.                 prev.insertAfter(new Item(b));
  173.  
  174.             b = b.next; // Идём дальше во втором
  175.  
  176.             prev = prev.next; // Следующий поиск начнём с вставленного или существующего элемента
  177.         }
  178.         unionTail(RES, prev, b, B.tail);// Вызываем метод объединения хвостов множеств
  179.         return RES;
  180.     }
  181.  
  182.     // Метод завершает объединение множеств, вызывается в случае когда в одном из множеств дошли до хвоста
  183.     // Модифицирует результирующее множество
  184.     private void  unionTail(Set RES, Item prev, Item b, Item tailB){
  185.         /*if (a == tail && b == tailB) { // Если дошли до хвостов в обоих множествах, вставляем в порядке возрастания
  186.             if (a.val < b.val) {
  187.                 r.insertAfter(new Item(a));
  188.                 r = r.next;
  189.                 r.insertAfter(new Item(b));
  190.             } else if (a.val > b.val) {
  191.                 r.insertAfter(new Item(b));
  192.                 r = r.next;
  193.                 r.insertAfter(new Item(a));
  194.             } else { // Если равны
  195.                 r.insertAfter(new Item(a));
  196.             }
  197.             r = r.next;
  198.             return r;
  199.         }
  200.  
  201.         // Переставляем указатели так чтобы дошли до конца в первом
  202.         Item secTail = tailB, temp;
  203.         if (b == tailB) {
  204.             temp = a;
  205.             a = b;
  206.             b = temp;
  207.             secTail = tail;
  208.         }
  209.  
  210.         while (b != secTail && b.val < a.val){ // доходим до неменьшего элемента второго списка (или конца)
  211.             r.insertAfter(new Item(b));
  212.             r = r.next;
  213.             b = b.next;
  214.         }
  215.         r.insertAfter(new Item(a)); // Вставляем хвост первого списка
  216.         r = r.next;
  217.         if (a.val == b.val)  // если во втором списке элемент равен хвосту первого, пропускаем его
  218.             b = b.next;
  219.  
  220.         while (b != secTail){ // проходим до конца второго списка и вставляем
  221.             r.insertAfter(new Item(b));
  222.             r = r.next;
  223.             b = b.next;
  224.         }
  225.  
  226.         r.insertAfter(new Item(b)); // Вставляем хвост второго списка
  227.         r = r.next;
  228.         return r;
  229.          */
  230.  
  231.         // Если дошли до обоих хвостов
  232.         if (b == tailB && prev.next == RES.tail){
  233.             if (b.val < RES.tail.val){
  234.                 prev.insertAfter(new Item(b));
  235.             } else if (b.val > RES.tail.val) {
  236.                 RES.tail.insertAfter(new Item(b));
  237.                 RES.tail = RES.tail.next;
  238.             }
  239.             return;
  240.         }
  241.  
  242.         // Если дошли до конца второго, но не до хвоста первого
  243.         if (b == tailB){
  244.             if (prev.next.val != b.val) // Если хвоста второго нет в первом, добавляем
  245.                 prev.insertAfter(new Item(b));
  246.             return;
  247.         }
  248.  
  249.  
  250.         // Если не дошли до хвоста второго но прошли хвост первого
  251.  
  252.         if (b.val == RES.tail.val) //Если элемент второго равен хвосту первого, пропускаем его
  253.             b = b.next;
  254.  
  255.         while (b != tailB) { // Добавляем после хвоста
  256.             RES.tail.insertAfter(new Item(b));
  257.             RES.tail = RES.tail.next; // Двигаем хвост
  258.             b = b.next;
  259.         }
  260.  
  261.         RES.tail.insertAfter(new Item(b)); // Вставляем хвост второго множества в конец
  262.         RES.tail = RES.tail.next; // Двигаем хвост
  263.     }
  264.  
  265.     public Set UNION(Set B) {
  266.         // если один из них пустой или указатели совпадают то вернуть копию текущего или другого
  267.         if (B == null || B.tail == null || B == this) return new Set(this);
  268.         if (tail == null) return new Set(B);
  269.         // вызываем union
  270.         return union(B);
  271.     }
  272.  
  273.     public Set INTERSECTION(Set B) { // при удалении проверять хвост ли это
  274.         if (B == this) return new Set(this); // если указатели совпадают то вернуть копию текущего
  275.         if (B == null || B.tail == null || tail == null) return new Set(start, end); // если хоть один пустой вернуть пустую копию текущего
  276.  
  277.         // Результирующие границы итогового множества
  278.         int resStart = (start < B.start ? start : B.start);
  279.         int resEnd = (end>B.end ? end : B.end);
  280.  
  281.         // Создать пустое множество
  282.         Set RES = new Set(resStart, resEnd);
  283.  
  284.  
  285.         Item a = tail.next, b = B.tail.next; // Указатели для прохода по спискам
  286.         while (a != tail && b != B.tail && a.val != b.val){ // Ищем первое пересечение
  287.             if (a.val < b.val){ // если в А число меньше идём дальше в первом
  288.                 a = a.next;
  289.             } else
  290.                 b = b.next; // иначе идём дальше во втором
  291.         }
  292.  
  293.         if (a == tail || b == B.tail) {
  294.             if (a.val == b.val) {
  295.                 RES.tail = new Item(a); // Вставляем первый элемент
  296.                 RES.tail.next = RES.tail;
  297.             } return RES;
  298.         }
  299.  
  300.         RES.tail = new Item(a); // Вставляем первый элемент
  301.         RES.tail.next = RES.tail; //
  302.  
  303.         a=a.next;
  304.         b=b.next;
  305.         Item r = RES.tail;
  306.  
  307.         while (a != tail && b != B.tail){ // Вставка пока не дошли до одного из хвостов
  308.             if (a.val == b.val){
  309.                 r.insertAfter(new Item(a));
  310.                 r = r.next;
  311.                 a=a.next;
  312.                 b=b.next;
  313.             }
  314.             if (a.val < b.val){ // если в А число меньше идём дальше в первом
  315.                 a = a.next;
  316.             } else
  317.                 b = b.next; // иначе идём дальше во втором
  318.         }
  319.  
  320.  
  321.         if (a == tail && b == B.tail) { // Если дошли до хвостов в обоих множествах, вставляем если совпадают
  322.             if (a.val == b.val) {
  323.                 r.insertAfter(new Item(a));
  324.                 r = r.next;
  325.             }
  326.             RES.tail = r; // Переставляем хвост в конец
  327.             return RES;
  328.         }
  329.  
  330.         // Переставляем указатели так чтобы дошли до конца в первом
  331.         Item secTail = B.tail, temp;
  332.         if (b == B.tail) {
  333.             temp = a;
  334.             a = b;
  335.             b = temp;
  336.             secTail = tail;
  337.         }
  338.  
  339.         while (b != secTail && b.val < a.val) // доходим до неменьшего элемента второго списка (или конца)
  340.             b = b.next;
  341.  
  342.         if (a.val == b.val) { // если во втором списке элемент равен хвосту второго, вставляем
  343.             r.insertAfter(new Item(b));
  344.             r = r.next;
  345.         }
  346.  
  347.         RES.tail = r; // Переставляем хвост в конец
  348.         return RES;
  349.     }
  350.  
  351.     public Set DIFFERENCE(Set B){
  352.         if (B == null || B.tail == null) return new Set(this); // если второй пустой вернуть копию текущего
  353.         if (B == this ||   tail == null) return new Set(start, end); // если указатели совпадают то вернуть пустую копию текущего
  354.  
  355.         Item a = tail.next; // Указатели для прохода по спискам
  356.         Item Bprev = findPrevItem(B.tail, a.val); // Первый неменьший элемент второго
  357.  
  358.         if (Bprev.next == B.tail && Bprev.next.val != a.val) // Если во втором todo хвост второго в первом
  359.             return new Set(this);
  360.  
  361.         Item b = Bprev.next;
  362.  
  363.         // Создать пустое множество
  364.         Set RES = new Set(start, end);
  365.  
  366.         while (a.val == b.val && a != tail && b != B.tail){ // Ищем первое непересечение
  367.             a = a.next;
  368.             Bprev = findPrevItem(b, a.val); // Доходим до неменьшего во втором
  369.             b = Bprev.next; // Сдвигаем во втором до найденного
  370.         }
  371.  
  372.         if (a == tail || b == B.tail) { // Если дошли до конца одного из списков
  373.             if (a.val != b.val) { // Если они элементы не совпадают
  374.                 RES.tail = new Item(a); // Вставляем первый элемент
  375.                 RES.tail.next = RES.tail;
  376.             } return RES; // Возвращаем либо пустой, либо с одним элементом
  377.         }
  378.  
  379.         RES.tail = new Item(a); // Вставляем первый элемент
  380.         RES.tail.next = RES.tail; //
  381.  
  382.         a=a.next;
  383.         Bprev = findPrevItem(b, a.val); // Доходим до неменьшего во втором
  384.         b = Bprev.next; // Сдвигаем во втором до найденного
  385.         Item r = RES.tail;
  386.  
  387.         while (a != tail && b != B.tail){
  388.             if (a.val == b.val){ // если значения совпадают, идём дальше
  389.                 a = a.next;
  390.                 Bprev = findPrevItem(b, a.val); // Доходим до неменьшего во втором
  391.                 b = Bprev.next; // Сдвигаем во втором до найденного
  392.             }
  393.             else { // Иначе добавляем элемент первого
  394.                 r.insertAfter(new Item(a));
  395.                 a = a.next;
  396.                 r = r.next;
  397.             }
  398.         }
  399.  
  400.         // Дошли до конца в первом списке (если оба дошли до хвоста то тоже работает)
  401.         if (a == tail){
  402.             if (a.val != b.val){ // если хвост первого списка не находится во втором добавляем его
  403.                 r.insertAfter(new Item(a));
  404.                 r = r.next;
  405.             }
  406.         } else { // Иначе дошли до конца во втором списке
  407.             while (a != tail) { // Копируем хвост первого списка в результат
  408.                 if (b.val != a.val) { // Если хвост второго списка не совпадает с элементом то добавляем этот элемент
  409.                     r.insertAfter(new Item(a));
  410.                     r = r.next;
  411.                 }
  412.                 a = a.next; // двигаемся дальше в списке
  413.             }
  414.             r.insertAfter(new Item(a)); // Вставка хвоста первого
  415.             r = r.next;
  416.         }
  417.         RES.tail = r; // Перемещаем хвост в конец
  418.         return RES;
  419.     }
  420.  
  421.     public Set MERGE(Set B){
  422.         // если один из них пустой или указатели совпадают то вернуть копию текущего или другого
  423.         if (B == null || B.tail == null || B == this) return new Set(this);
  424.         // вызываем union
  425.         return union(B);
  426.     }
  427.  
  428.     public boolean MEMBER(int x){
  429.         // проверка лежит ли х в промежутке
  430.         if (x < start || x > end) return false;
  431.         // вызвать проверку
  432.         return isInSet(x);
  433.     }
  434.  
  435.     public void MAKENULL(){
  436.         tail = null;
  437.     }
  438.  
  439.     public void INSERT(int x){
  440.         //проверка что х в границах
  441.         if (x < start || x > end) return;
  442.  
  443.         //вставка если список пустой
  444.         if (tail == null) {
  445.             tail = new Item(x);
  446.             tail.next = tail;
  447.             return;
  448.         }
  449.  
  450.         // Если вставка перед головой
  451.         if (tail.next.val > x)
  452.             tail.insertAfter(new Item(x));
  453.  
  454.         // если элемент вставляется после хвоста
  455.         if (tail.val < x){
  456.             tail.insertAfter(new Item(x));
  457.             tail = tail.next; // Двигаем хвост
  458.         }
  459.  
  460.         //найти элемент предыдущий потенциальному местонахождению искомого
  461.         Item prev = findPrevItem(tail, x);
  462.         //если искомого элемента нет, вставляем
  463.         if (prev.next.val != x) prev.insertAfter(new Item(x));
  464.         //иначе ничего не делаем
  465.     }
  466.  
  467.     public void DELETE(int x){
  468.         // проверка что х в границах
  469.         if (x < start || x > end) return;
  470.  
  471.         // Если искомый элемент должен быть после хвоста или до головы то его нет в списке
  472.         if (tail.val < x || tail.next.val > x) return;
  473.  
  474.         // если удаляем хвост
  475.         if (tail.val == x){
  476.             if (tail.next == tail) tail = null; // Был один элемент
  477.             else{
  478.                 Item prev = findPrevItem(tail, x);
  479.                 tail = prev; // Двигаем хвост назад
  480.                 prev.deleteAfter();
  481.             }
  482.             return;
  483.         }
  484.         //найти элемент предыдущий потенциальному местонахождению искомого
  485.         Item prev = findPrevItem(tail, x);
  486.  
  487.         // Если после найденного есть такой элемент
  488.         if (prev.next.val == x) prev.deleteAfter();
  489.         // Иначе ничего не делаем
  490.     }
  491.  
  492.     public void ASSIGN(Set A){
  493.         // если один и тот же объект или дан пустой
  494.         if (A == null || A == this) return;
  495.         // Скопировать границы
  496.         start = A.start;
  497.         end = A.end;
  498.         // Скопировать элементы
  499.         tail = copylist(A.tail);
  500.     }
  501.  
  502.     public int MIN(){
  503.         if (tail == null) throw new SetException("Множество пустое, нет минимального элемента"); // Если список пустой
  504.         return tail.next.val; // Иначе смотрим в голову
  505.     }
  506.  
  507.     public int MAX(){
  508.         if (tail == null) throw new SetException("Множество пустое, нет максимального элемента"); // Если список пустой
  509.         return tail.val; // Иначе смотрим в хвост
  510.     }
  511.  
  512.     public boolean EQUAL(Set B) {// Если границы разные но элементы совпадают то всё равно true
  513.         if (tail.val != B.tail.val) return false; // Если в хвостах различные элементы
  514.  
  515.         // a, b указатели прохода по спискам
  516.         Item a = tail.next, b = B.tail.next;
  517.  
  518.         //пока не дойдём до конца хоть одного из списков проверяем что все равны
  519.         while (a != tail && b != B.tail){
  520.             if (a.val != b.val) return false;
  521.             a = a.next;
  522.             b = b.next;
  523.         }
  524.         //если после прохода хоть один из указателей не дошёл до хвоста или они разные вернуть ложь
  525.         if (!(a == tail && b == tail))
  526.             return false;
  527.  
  528.         return true;
  529.     }
  530.  
  531.     public Set FIND(Set B, int x){
  532.         // если множества пересекаются бросить исключение
  533.         if (isCrossing(B)) return null;
  534.  
  535.         // Проверяем на каждом множестве если оно содержит х
  536.         if (start<x && x<end && isInSet(x))
  537.             return this;
  538.         else if (B.start<x && x<B.end && B.isInSet(x))
  539.             return B;
  540.  
  541.         return null; // Если ни в одном множестве нет этого элемента
  542.     }
  543.  
  544.     public void PRINT(){
  545.         if (tail == null) return;
  546.          // Проходом по кольцевому списку выводим
  547.         for (Item fir = tail.next; fir != tail; fir = fir.next)
  548.             System.out.printf("%d ", fir.val);
  549.         System.out.println(tail.val); // Выводим последний
  550.     }
  551. }
  552.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement