diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..028e044
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..a64ad2d
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
new file mode 100644
index 0000000..0dd4b35
--- /dev/null
+++ b/.idea/kotlinc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/KotlinJavaRuntime.xml b/.idea/libraries/KotlinJavaRuntime.xml
new file mode 100644
index 0000000..1a7265d
--- /dev/null
+++ b/.idea/libraries/KotlinJavaRuntime.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/io_reactivex_rxjava3_rxjava_3_1_6.xml b/.idea/libraries/io_reactivex_rxjava3_rxjava_3_1_6.xml
new file mode 100644
index 0000000..087228e
--- /dev/null
+++ b/.idea/libraries/io_reactivex_rxjava3_rxjava_3_1_6.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/org_jetbrains_annotations_15_0.xml b/.idea/libraries/org_jetbrains_annotations_15_0.xml
new file mode 100644
index 0000000..8020b4e
--- /dev/null
+++ b/.idea/libraries/org_jetbrains_annotations_15_0.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml
new file mode 100644
index 0000000..e96534f
--- /dev/null
+++ b/.idea/uiDesigner.xml
@@ -0,0 +1,124 @@
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 585124c..e573e80 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -1,9 +1,30 @@
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -15,300 +36,88 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
+
@@ -316,12 +125,12 @@
-
-
+
+
-
+
@@ -329,12 +138,12 @@
-
-
+
+
-
+
@@ -342,12 +151,12 @@
-
-
+
+
-
+
@@ -355,12 +164,12 @@
-
-
+
+
-
+
@@ -369,22 +178,35 @@
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -407,418 +229,47 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
- file://$PROJECT_DIR$/src/ru/arhiser/multithreading/synchro/Syncro.java
- 4
-
-
+ file://$PROJECT_DIR$/src/ru/arhiser/visual/engine/animator/evaluator/RGBLinearEvaluator.java
+ 20
+
+
+
+ file://$PROJECT_DIR$/src/ru/arhiser/visual/engine/animator/PropertyAnimator.java
+ 29
+
+
+
+
+
+
+
+
-
-
-
- startIndex != middleIndex && endIndex != middleIndex
- JAVA
- EXPRESSION
-
-
- array[middleIndex]
- JAVA
- EXPRESSION
-
-
- index1 >= src1End
- JAVA
- EXPRESSION
-
-
- src2[index2]
- JAVA
- EXPRESSION
-
-
- src1[index1]
- JAVA
- EXPRESSION
-
-
- src1End - src1Start + src2End - src2Start
- JAVA
- EXPRESSION
-
-
- src1[index1] <= src2[index2]
- JAVA
- EXPRESSION
-
-
- index1 < src1Start + size
- JAVA
- EXPRESSION
-
-
- index1 < src1.length
- JAVA
- EXPRESSION
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ ru.arhiser.imageprocess2.*
+
+
+ ru.arhiser.huffman_adapt.*
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 9facdd8..f2ae254 100644
--- a/README.md
+++ b/README.md
@@ -32,3 +32,13 @@ Java. Решето Эратосфена. Проверка числа но про
Java. Алгоритм Хаффмана для компрессии данных.|https://youtu.be/OQrwOywESGg|https://github.com/Arhiser/java_tutorials/blob/master/src/ru/arhiser/huffman/Main.java
Java. Обращение односвязного списка.|https://youtu.be/Nzz4i1QWmJw|https://github.com/Arhiser/java_tutorials/blob/master/src/ru/arhiser/linkedlist/Main.java
Java. Рисуем звезды в 3D пространстве.|https://youtu.be/BgbIh5ktOs4|https://github.com/Arhiser/java_tutorials/tree/master/src/ru/arhiser/stars
+Java. Сортировка подсчетом.|https://youtu.be/WBS8qlrry0U|https://github.com/Arhiser/java_tutorials/tree/master/src/ru/arhiser/sort/count
+Java. Сортировка вставками.|https://youtu.be/jywoZ2XaQoM|https://github.com/Arhiser/java_tutorials/blob/master/src/ru/arhiser/sort/insertion/InsertionSort.java
+Java. Префиксное дерево.|https://youtu.be/-DGJuakdiYU|https://github.com/Arhiser/java_tutorials/blob/master/src/ru/arhiser/prefix_tree/Main.java
+Java. Адаптивная компрессия Хаффмана.|https://youtu.be/IEe3qkdZ99c|https://github.com/Arhiser/java_tutorials/tree/master/src/ru/arhiser/huffman_adapt/digital
+Java. Алгоритм генерации фрактального шума|https://youtu.be/a-j8vgLfUqA|https://github.com/Arhiser/java_tutorials/tree/master/src/ru/arhiser/fract_noise
+Java. Задача о рюкзаке. Динамическое программирование.|https://youtu.be/wcjqBf2qRe0|https://github.com/Arhiser/java_tutorials/tree/master/src/ru/arhiser/knapsack
+Java. Сортировка расческой. От пузырька до расчески.|https://youtu.be/ywGK-_3znMw|https://github.com/Arhiser/java_tutorials/tree/master/src/ru/arhiser/sort/comb
+Java. Системы счисления. Алгоритм перевода в произвольную систему счисления.|https://youtu.be/O9jc8_5wcuQ|https://github.com/Arhiser/java_tutorials/blob/master/src/ru/arhiser/calculus/Main.java
+Java. Dithering. Алгоритм генерации черно-белых изображений.|https://youtu.be/oAsaB90f2Y0|https://github.com/Arhiser/java_tutorials/blob/master/src/ru/arhiser/dithering/Main.java
+Java. Bogosort. Случайная сортировка.|https://youtu.be/4Kpb_TTgdmU|https://github.com/Arhiser/java_tutorials/blob/master/src/ru/arhiser/sort/bogo/Main.java
diff --git a/src/ru/arhiser/Utils.java b/src/ru/arhiser/Utils.java
new file mode 100644
index 0000000..ae6a79b
--- /dev/null
+++ b/src/ru/arhiser/Utils.java
@@ -0,0 +1,51 @@
+package ru.arhiser;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+
+public class Utils {
+
+ public static void showImageWindow(Image image) {
+ showImageWindow(image, image.getWidth(null), image.getHeight(null));
+ }
+
+ public static void showImageWindow(Image image, int width, int height) {
+
+ if (image.getWidth(null) != width || image.getHeight(null) != height) {
+ image = image.getScaledInstance(width, height, Image.SCALE_SMOOTH);
+ }
+
+ JFrame frame = new JFrame();
+ frame.setSize(width, height);
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ JLabel picLabel = new JLabel(new ImageIcon(image));
+
+ BorderLayout borderLayout = new BorderLayout();
+ frame.getContentPane().setLayout(borderLayout);
+ frame.getContentPane().add(picLabel, BorderLayout.CENTER);
+
+ frame.setVisible(true);
+ }
+
+ public static void measureTime(Runnable task, String taskName) {
+ long startTime = System.currentTimeMillis();
+ task.run();
+ long elapsed = System.currentTimeMillis() - startTime;
+ System.out.println(taskName + ": " + elapsed + " ms");
+ }
+
+ public static void assertTrue(boolean condition) {
+ if (!condition) {
+ throw new AssertionError();
+ }
+ }
+
+ public static BufferedImage toBufferedImage(Image img) {
+ BufferedImage bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
+ Graphics2D bGr = bimage.createGraphics();
+ bGr.drawImage(img, 0, 0, null);
+ bGr.dispose();
+ return bimage;
+ }
+}
diff --git a/src/ru/arhiser/calculus/Main.java b/src/ru/arhiser/calculus/Main.java
new file mode 100644
index 0000000..83eb891
--- /dev/null
+++ b/src/ru/arhiser/calculus/Main.java
@@ -0,0 +1,35 @@
+package ru.arhiser.calculus;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Main {
+
+ public static void main(String[] args) {
+ System.out.println(getInRadix(255, 23));
+ }
+
+ public static String getInRadix(int number, int radix) {
+ List digits = getDigitTable();
+ if (radix < 2 || radix >= digits.size() || number < 0) {
+ throw new IllegalArgumentException();
+ }
+ StringBuilder valueStr = new StringBuilder();
+ while (number > 0) {
+ valueStr.insert(0, digits.get(number % radix));
+ number = number / radix;
+ }
+ return valueStr.toString();
+ }
+
+ private static List getDigitTable() {
+ ArrayList digits = new ArrayList<>();
+ for (char i = '0'; i <= '9'; i++) {
+ digits.add(i);
+ }
+ for (char i = 'A'; i <= 'Z'; i++) {
+ digits.add(i);
+ }
+ return digits;
+ }
+}
diff --git a/src/ru/arhiser/dithering/IMG_20180824_121235.jpg b/src/ru/arhiser/dithering/IMG_20180824_121235.jpg
new file mode 100644
index 0000000..89fe75f
Binary files /dev/null and b/src/ru/arhiser/dithering/IMG_20180824_121235.jpg differ
diff --git a/src/ru/arhiser/dithering/Main.java b/src/ru/arhiser/dithering/Main.java
new file mode 100644
index 0000000..143f8c0
--- /dev/null
+++ b/src/ru/arhiser/dithering/Main.java
@@ -0,0 +1,75 @@
+package ru.arhiser.dithering;
+
+import ru.arhiser.Utils;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferInt;
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+
+import static java.awt.image.BufferedImage.TYPE_INT_RGB;
+
+public class Main {
+ public static void main(String[] args) throws IOException {
+ System.setProperty("sun.java2d.uiScale", "1");
+
+ BufferedImage picture = ImageIO.read(new File(".\\src\\ru\\arhiser\\dithering\\IMG_20180824_121235.jpg"));
+
+ picture = Utils.toBufferedImage(picture.getScaledInstance(3840, 2160, Image.SCALE_SMOOTH));
+
+ int[] pixels = ((DataBufferInt)picture.getRaster().getDataBuffer()).getData();
+
+ Arrays.setAll(pixels, i -> {
+ int color = pixels[i];
+ int bwColor = (int) (0.0722 * (color & 0xff) + 0.7152 * (color >> 8 & 0xff) + 0.2126 * (color >> 16 & 0xff));
+ return 0xff000000 | bwColor & 0xff | ((bwColor & 0xff) << 8) | ((bwColor & 0xff) << 16);
+ });
+
+ picture = dithering(picture);
+
+/*
+ int[] noise = new int[pixels.length];
+ Arrays.setAll(noise, i -> 128 - (int)(Math.random() * 255));
+
+ Arrays.setAll(pixels, i -> {
+ int color = pixels[i];
+ int bwColor = color & 0xff;
+ int sum = bwColor + noise[i];
+ if (sum > 255) {
+ sum = 255;
+ }
+ if (sum < 0) {
+ sum = 0;
+ }
+ return 0xff000000 | sum & 0xff | ((sum & 0xff) << 8) | ((sum & 0xff) << 16);
+ });
+
+ Arrays.setAll(pixels, i -> {
+ int color = pixels[i];
+ int bwColor = color & 0xff;
+ return bwColor > 127 ? 0xffffffff : 0xff000000;
+ });
+*/
+ Utils.showImageWindow(picture);
+ }
+
+ private static BufferedImage dithering(BufferedImage img) {
+ BufferedImage bwOnlyImage = new BufferedImage(img.getWidth(), img.getHeight(), TYPE_INT_RGB);
+ int[] destPixels = ((DataBufferInt) bwOnlyImage.getRaster().getDataBuffer()).getData();
+ int[] sourcePixels = ((DataBufferInt) img.getRaster().getDataBuffer()).getData();
+ int size = img.getHeight() * img.getWidth();
+
+ int error = 0;
+
+ for (int i = 0; i < size; i++) {
+ int pixel = 0xff & sourcePixels[i];
+ int value = pixel > error ? 255 : 0;
+ error += value - pixel;
+ destPixels[i] = 0xff000000 | value << 16 | value << 8 | value;
+ }
+ return bwOnlyImage;
+ }
+}
diff --git a/src/ru/arhiser/dithering/bw_dithering.png b/src/ru/arhiser/dithering/bw_dithering.png
new file mode 100644
index 0000000..7a823b4
Binary files /dev/null and b/src/ru/arhiser/dithering/bw_dithering.png differ
diff --git a/src/ru/arhiser/dithering/out_bw_noised.png b/src/ru/arhiser/dithering/out_bw_noised.png
new file mode 100644
index 0000000..19d545d
Binary files /dev/null and b/src/ru/arhiser/dithering/out_bw_noised.png differ
diff --git a/src/ru/arhiser/dithering/out_gray_noised.png b/src/ru/arhiser/dithering/out_gray_noised.png
new file mode 100644
index 0000000..f104e4e
Binary files /dev/null and b/src/ru/arhiser/dithering/out_gray_noised.png differ
diff --git a/src/ru/arhiser/fract_noise/FractalNoise.java b/src/ru/arhiser/fract_noise/FractalNoise.java
new file mode 100644
index 0000000..7b5f714
--- /dev/null
+++ b/src/ru/arhiser/fract_noise/FractalNoise.java
@@ -0,0 +1,34 @@
+package ru.arhiser.fract_noise;
+
+import java.util.ArrayList;
+
+public class FractalNoise {
+
+ int baseScale;
+
+ Random random;
+
+ ArrayList octaves = new ArrayList<>();
+
+ public FractalNoise(int baseScale, Random random, int octavesCount) {
+ this.baseScale = baseScale;
+ this.random = random;
+
+ int scale = baseScale;
+ for (int i = 0; i < octavesCount; i++) {
+ octaves.add(new Noise(scale, random));
+ scale = scale / 2;
+ }
+ }
+
+ public float getValue(int x, int y) {
+ float sum = 0;
+ float fraction = 0.5f;
+
+ for(Noise noise: octaves) {
+ sum += noise.getValue(x, y) * fraction;
+ fraction *= 0.5;
+ }
+ return sum;
+ }
+}
diff --git a/src/ru/arhiser/fract_noise/Main.java b/src/ru/arhiser/fract_noise/Main.java
new file mode 100644
index 0000000..f620a58
--- /dev/null
+++ b/src/ru/arhiser/fract_noise/Main.java
@@ -0,0 +1,31 @@
+package ru.arhiser.fract_noise;
+
+import ru.arhiser.Utils;
+
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferInt;
+
+public class Main {
+
+ private static final int IMAGE_WIDTH = 1920;
+ private static final int IMAGE_HEIGHT = 1080;
+
+ public static void main(String[] args) {
+
+ BufferedImage image = new BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
+
+ FractalNoise fractalNoise = new FractalNoise(512,
+ new Random(image.getWidth(), 100000), 9);
+
+ int[] pixels = ((DataBufferInt)image.getRaster().getDataBuffer()).getData();
+ int pixelIndex = 0;
+ for (int i = 0; i < image.getHeight(); i++) {
+ for (int j = 0; j < image.getWidth(); j++) {
+ int value = 0xff & (int)(fractalNoise.getValue(j, i) * 255);
+ pixels[pixelIndex++] = 0xff000000 | value << 16 | value << 8 | value;
+ }
+ }
+
+ Utils.showImageWindow(image, IMAGE_WIDTH, IMAGE_HEIGHT);
+ }
+}
diff --git a/src/ru/arhiser/fract_noise/Noise.java b/src/ru/arhiser/fract_noise/Noise.java
new file mode 100644
index 0000000..aed317a
--- /dev/null
+++ b/src/ru/arhiser/fract_noise/Noise.java
@@ -0,0 +1,40 @@
+package ru.arhiser.fract_noise;
+
+public class Noise {
+
+ int scale;
+
+ Random random;
+
+ public Noise(int scale, Random random) {
+ this.scale = scale;
+ this.random = random;
+ }
+
+ public float getValue(int x, int y) {
+ int xgrid = x / scale;
+ int ygrid = y / scale;
+ int xgridNext = xgrid + 1;
+ int ygridNext = ygrid + 1;
+
+ int xStart = xgrid * scale;
+ int xEnd = xgridNext * scale;
+ int yStart = ygrid * scale;
+ int yEnd = ygridNext * scale;
+
+ float value12 = random.getRandomValue(xgrid, ygrid);
+ float value22 = random.getRandomValue(xgridNext, ygrid);
+ float value21 = random.getRandomValue(xgridNext, ygridNext);
+ float value11 = random.getRandomValue(xgrid, ygridNext);
+
+ float w12 = ((float) (xEnd - x) * (yEnd - y)) / ((xEnd - xStart) * (yEnd - yStart));
+ float w22 = ((float) (x - xStart) * (yEnd - y)) / ((xEnd - xStart) * (yEnd - yStart));
+ float w21 = ((float) (x - xStart) * (y - yStart)) / ((xEnd - xStart) * (yEnd - yStart));
+ float w11 = ((float) (xEnd - x) * (y - yStart)) / ((xEnd - xStart) * (yEnd - yStart));
+
+ float value = value11 * w11 + value12 * w12 + value21 * w21 + value22 * w22;
+
+ return value;
+ }
+
+}
diff --git a/src/ru/arhiser/fract_noise/Random.java b/src/ru/arhiser/fract_noise/Random.java
new file mode 100644
index 0000000..82e088e
--- /dev/null
+++ b/src/ru/arhiser/fract_noise/Random.java
@@ -0,0 +1,20 @@
+package ru.arhiser.fract_noise;
+
+public class Random {
+
+ int[] table;
+
+ int lineWidth;
+
+ public Random(int lineWidth, int size) {
+ table = new int[size];
+ for (int i = 0; i < size; i++) {
+ table[i] = Math.random() >= 0.5 ? 1 : 0;
+ }
+ this.lineWidth = lineWidth;
+ }
+
+ public int getRandomValue(int x, int y) {
+ return table[(x + y * lineWidth) % table.length];
+ }
+}
diff --git a/src/ru/arhiser/funcops/monad/FutureMain.java b/src/ru/arhiser/funcops/monad/FutureMain.java
new file mode 100644
index 0000000..19b7059
--- /dev/null
+++ b/src/ru/arhiser/funcops/monad/FutureMain.java
@@ -0,0 +1,17 @@
+package ru.arhiser.funcops.monad;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+
+public class FutureMain {
+ public static void main(String[] args) throws ExecutionException, InterruptedException {
+ CompletableFuture completableFuture
+ = CompletableFuture.supplyAsync(() -> "Hello");
+
+ CompletableFuture future = completableFuture
+ .thenApply(s -> s + " World")
+ .thenApply(s -> s + "\n completed!");
+
+ System.out.println(future.get());
+ }
+}
diff --git a/src/ru/arhiser/funcops/monad/LazyMain.java b/src/ru/arhiser/funcops/monad/LazyMain.java
new file mode 100644
index 0000000..544b7af
--- /dev/null
+++ b/src/ru/arhiser/funcops/monad/LazyMain.java
@@ -0,0 +1,56 @@
+package ru.arhiser.funcops.monad;
+
+import ru.arhiser.funcops.Client;
+
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+public class LazyMain {
+
+ public static void main(String[] args) {
+
+ Client client = new Client("111 222", 15, true);
+ Lazy composed = Lazy.from(client)
+ .map(Client::getName)
+ .map(s -> s.split(" "))
+ .map(c -> {
+ System.out.println(c[0]);
+ return c[0];
+ });
+
+ composed.get();
+ }
+
+ public static class Lazy {
+ T value;
+
+ Supplier supplier;
+
+ private Lazy(T value) {
+ this.value = value;
+ }
+
+ private Lazy(Supplier supplier) {
+ this.supplier = supplier;
+ }
+
+ public static Lazy from(T value) {
+ return new Lazy<>(value);
+ }
+
+ public T get() {
+ if (value == null) {
+ value = supplier.get();
+ }
+ return value;
+ }
+
+ public Lazy map(Function mapFunc) {
+ return new Lazy<>(() -> mapFunc.apply(get()));
+ }
+
+ public Lazy flatMap(Function> mapFunc) {
+ return mapFunc.apply(value);
+ }
+ }
+}
diff --git a/src/ru/arhiser/funcops/monad/Main.java b/src/ru/arhiser/funcops/monad/Main.java
new file mode 100644
index 0000000..ad4b95a
--- /dev/null
+++ b/src/ru/arhiser/funcops/monad/Main.java
@@ -0,0 +1,39 @@
+package ru.arhiser.funcops.monad;
+
+import ru.arhiser.funcops.Client;
+
+import java.util.function.Function;
+
+public class Main {
+ public static void main(String[] args) {
+ Client client = new Client("Harry Carter", 15, true);
+ Monad.from(client)
+ .map(Client::getName)
+ .map(s -> s.split(" "))
+ .map(c -> {
+ System.out.println(c[0]);
+ return c[0];
+ });
+
+ }
+
+ public static class Monad {
+ final T value;
+
+ private Monad(T value) {
+ this.value = value;
+ }
+
+ public static Monad from(T value) {
+ return new Monad<>(value);
+ }
+
+ public Monad map(Function mapFunc) {
+ return flatMap(val -> new Monad<>(mapFunc.apply(val)));
+ }
+
+ public Monad flatMap(Function> mapFunc) {
+ return mapFunc.apply(value);
+ }
+ }
+}
diff --git a/src/ru/arhiser/funcops/monad/OptionalMain.java b/src/ru/arhiser/funcops/monad/OptionalMain.java
new file mode 100644
index 0000000..1860819
--- /dev/null
+++ b/src/ru/arhiser/funcops/monad/OptionalMain.java
@@ -0,0 +1,46 @@
+package ru.arhiser.funcops.monad;
+
+import ru.arhiser.funcops.Client;
+
+import java.util.function.Function;
+
+public class OptionalMain {
+
+ public static void main(String[] args) {
+ Client client = new Client("Harry Carter", 15, true);
+ Optional.from(client)
+ .map(Client::getName)
+ .map(s -> s.split(" "))
+ .map(c -> {
+ System.out.println(c[0]);
+ return c[0];
+ });
+ }
+
+ public static class Optional {
+
+ private static Optional> empty = new Optional<>(null);
+
+ T value;
+
+ private Optional(T value) {
+ this.value = value;
+ }
+
+ public static Optional from(T value) {
+ if (value != null) {
+ return new Optional<>(value);
+ } else {
+ return (Optional) empty;
+ }
+ }
+
+ public Optional map(Function mapFunc) {
+ if (value != null) {
+ return new Optional(mapFunc.apply(value));
+ } else {
+ return (Optional) empty;
+ }
+ }
+ }
+}
diff --git a/src/ru/arhiser/huffman_adapt/digital/BitBuffer.java b/src/ru/arhiser/huffman_adapt/digital/BitBuffer.java
new file mode 100644
index 0000000..f187e2e
--- /dev/null
+++ b/src/ru/arhiser/huffman_adapt/digital/BitBuffer.java
@@ -0,0 +1,79 @@
+package ru.arhiser.huffman_adapt.digital;
+
+/**
+ * Класс реализующий битовый массив
+ */
+public class BitBuffer {
+ int size;
+ int current;
+ byte[] bytes;
+
+ private byte[] masks = new byte[] {0b00000001, 0b00000010, 0b00000100, 0b00001000,
+ 0b00010000, 0b00100000, 0b01000000, (byte) 0b10000000};
+
+ public BitBuffer(int size) {
+ this.size = size;
+ int sizeInBytes = size >> 3; // int sizeInBytes = size / 8;
+ if (size % 8 > 0) {
+ sizeInBytes = sizeInBytes + 1;
+ }
+ bytes = new byte[sizeInBytes];
+ }
+
+ public BitBuffer(int size, byte[] bytes) {
+ this.size = size;
+ this.bytes = bytes;
+ }
+
+ public void setCurrent(int current) {
+ this.current = current;
+ }
+
+ public int get(int index) {
+ int byteIndex = index >> 3; // int sizeInBytes = size / 8; оптимизация - замена деления битовыми операциями
+ int bitIndex = index & 0b111; // int bitIndex = index % 8;
+ return (bytes[byteIndex] & masks[bitIndex]) != 0 ? 1 : 0;
+ }
+
+ public void set(int index, int value) {
+ int byteIndex = index >> 3;
+ int bitIndex = index & 0b111;
+ if (value != 0) {
+ bytes[byteIndex] = (byte) (bytes[byteIndex] | masks[bitIndex]);
+ } else {
+ bytes[byteIndex] = (byte) (bytes[byteIndex] & ~masks[bitIndex]);
+ }
+ }
+
+ public void append(int value) {
+ int byteIndex = current >> 3;
+ int bitIndex = current & 0b111;
+ if (value != 0) {
+ bytes[byteIndex] = (byte) (bytes[byteIndex] | masks[bitIndex]);
+ } else {
+ bytes[byteIndex] = (byte) (bytes[byteIndex] & ~masks[bitIndex]);
+ }
+ current += 1;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < size; i++) {
+ sb.append(get(i) > 0 ? '1' : '0');
+ }
+ return sb.toString();
+ }
+
+ public int getSize() {
+ return size;
+ }
+
+ public int getSizeInBytes() {
+ return bytes.length;
+ }
+
+ public byte[] getBytes() {
+ return bytes;
+ }
+}
diff --git a/src/ru/arhiser/huffman_adapt/digital/BitToByteWriter.java b/src/ru/arhiser/huffman_adapt/digital/BitToByteWriter.java
new file mode 100644
index 0000000..4ade14f
--- /dev/null
+++ b/src/ru/arhiser/huffman_adapt/digital/BitToByteWriter.java
@@ -0,0 +1,59 @@
+package ru.arhiser.huffman_adapt.digital;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Класс, осуществляющий упаковку отдельных битов в байты
+ * методом writeBit() добавляем по одному биту, как только накопится 8 бит,
+ * они объединяются в байт, который записывается в целевой поток
+ * OutputStream target;
+ */
+public class BitToByteWriter {
+
+ int bitBuffer;
+
+ int bitWritten;
+ int bytesWritten;
+
+ OutputStream target;
+
+ public BitToByteWriter(OutputStream target) {
+ this.target = target;
+ }
+
+ public void close() throws IOException {
+ if ((bitWritten & 0b111) != 0) {
+ target.write(bitBuffer);
+ bytesWritten += 1;
+ }
+ target.flush();
+ target.close();
+ }
+
+ public void writeBit(int bit) throws IOException {
+ int bitIndex = bitWritten & 0b111;
+ int mask = 1 << bitIndex;
+ switch (bit) {
+ case 1:
+ bitBuffer |= mask;
+ break;
+ case 0:
+ bitBuffer &= ~mask;
+ break;
+ }
+ bitWritten += 1;
+ if (bitIndex + 1 == 8) {
+ target.write(bitBuffer);
+ bytesWritten += 1;
+ }
+ }
+
+ public void writeByte(int val) throws IOException {
+ int mask = 1;
+ for (int i = 0; i < 8; i++) {
+ writeBit((val & mask) > 0 ? 1 : 0);
+ mask <<= 1;
+ }
+ }
+}
diff --git a/src/ru/arhiser/huffman_adapt/digital/CodeTreeNode.java b/src/ru/arhiser/huffman_adapt/digital/CodeTreeNode.java
new file mode 100644
index 0000000..d9553d7
--- /dev/null
+++ b/src/ru/arhiser/huffman_adapt/digital/CodeTreeNode.java
@@ -0,0 +1,48 @@
+package ru.arhiser.huffman_adapt.digital;
+
+
+/**
+ * Класс для представления узла кодового дерева
+ */
+public class CodeTreeNode implements Comparable {
+
+ Integer content;
+ int weight;
+ CodeTreeNode left;
+ CodeTreeNode right;
+ CodeTreeNode parent;
+
+ public CodeTreeNode(Integer content, int weight) {
+ this.content = content;
+ this.weight = weight;
+ }
+
+ public CodeTreeNode(Integer content, int weight, CodeTreeNode left, CodeTreeNode right, CodeTreeNode parent) {
+ this.content = content;
+ this.weight = weight;
+ this.left = left;
+ this.right = right;
+ this.parent = parent;
+ }
+
+ @Override
+ public int compareTo(CodeTreeNode o) {
+ return o.weight - weight;
+ }
+
+ public int updateWeights() {
+ if (content != null) {
+ return weight;
+ } else {
+ int w = 0;
+ if (right != null) {
+ w += right.updateWeights();
+ }
+ if (left != null) {
+ w += left.updateWeights();
+ }
+ weight = w;
+ return weight;
+ }
+ }
+}
diff --git a/src/ru/arhiser/huffman_adapt/digital/CoderTestApp.java b/src/ru/arhiser/huffman_adapt/digital/CoderTestApp.java
new file mode 100644
index 0000000..6164c57
--- /dev/null
+++ b/src/ru/arhiser/huffman_adapt/digital/CoderTestApp.java
@@ -0,0 +1,65 @@
+package ru.arhiser.huffman_adapt.digital;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.TextEvent;
+import java.awt.event.TextListener;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+public class CoderTestApp {
+
+ public static void main(String[] args) {
+ JFrame frame = new JFrame();
+
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.getContentPane().setLayout(new GridLayout(3, 2, 1, 1));
+
+ TextField text = new TextField();
+ TextField encoded = new TextField();
+ TextField decoded = new TextField();
+ frame.getContentPane().add(new Label("Исходный текст:", Label.RIGHT));
+ frame.getContentPane().add(text);
+ frame.getContentPane().add(new Label("Сжатый текст:", Label.RIGHT));
+ frame.getContentPane().add(encoded);
+ frame.getContentPane().add(new Label("Раскодированный текст:", Label.RIGHT));
+ frame.getContentPane().add(decoded);
+
+ text.addTextListener(new TextListener() {
+ @Override
+ public void textValueChanged(TextEvent e) {
+ encodeAndDecode(text.getText(), encoded, decoded);
+ }
+ });
+
+ frame.setSize(800, text.getPreferredSize().height * 3);
+
+ frame.pack();
+ frame.setVisible(true);
+
+ text.setText("abbaacca");
+ }
+
+ private static void encodeAndDecode(String text, TextField encoded, TextField decoded) {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ HuffmanEncoderStream huffmanEncoderStream = new HuffmanEncoderStream(outputStream);
+ try {
+ huffmanEncoderStream.write(text.getBytes(StandardCharsets.US_ASCII));
+ huffmanEncoderStream.close();
+ encoded.setText(outputStream.toString());
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ ByteArrayOutputStream decodeResultStream = new ByteArrayOutputStream();
+ HuffmanDecoderStream huffmanDecoderStream = new HuffmanDecoderStream(decodeResultStream);
+ try {
+ huffmanDecoderStream.write(outputStream.toByteArray());
+ huffmanDecoderStream.close();
+ decoded.setText(decodeResultStream.toString());
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/src/ru/arhiser/huffman_adapt/digital/EncodingModel.java b/src/ru/arhiser/huffman_adapt/digital/EncodingModel.java
new file mode 100644
index 0000000..3e1ba79
--- /dev/null
+++ b/src/ru/arhiser/huffman_adapt/digital/EncodingModel.java
@@ -0,0 +1,16 @@
+package ru.arhiser.huffman_adapt.digital;
+
+import java.io.IOException;
+
+public interface EncodingModel {
+
+ void updateByCharacter(int value);
+
+ void writeCodeForCharacter(Integer value, BitToByteWriter bitWriter) throws IOException;
+
+ CodeTreeNode getTree();
+
+ CodeTreeNode getZeroNode();
+
+ boolean contains(int value);
+}
diff --git a/src/ru/arhiser/huffman_adapt/digital/EncodingModelRefreshing.java b/src/ru/arhiser/huffman_adapt/digital/EncodingModelRefreshing.java
new file mode 100644
index 0000000..da8865b
--- /dev/null
+++ b/src/ru/arhiser/huffman_adapt/digital/EncodingModelRefreshing.java
@@ -0,0 +1,173 @@
+package ru.arhiser.huffman_adapt.digital;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Модель компресии для адаптивного сжатия Хаффмана.
+ * Содержит кодовое дерево и логику его обновления по мере поступления новой информации.
+ * Отвечает за генерацию и запись оптимальных кодов в выходной поток
+ */
+public class EncodingModelRefreshing implements EncodingModel {
+
+ public final CodeTreeNode ZERO_NODE = new CodeTreeNode(null, 0); // узел для escape символа
+
+ private CodeTreeNode tree = ZERO_NODE; // кодовое дерево
+ private final List nodeList = new ArrayList<>(500); // упорядоченый по весам список узлов
+ private final BitBuffer bitBuffer = new BitBuffer(1024); // бувер для накопления бит кода очередного символа
+ private final CodeTreeNode[] nodeCache = new CodeTreeNode[256]; // таблица для быстрого поиска узла дерева для любого символа
+
+ public EncodingModelRefreshing() {
+ nodeList.add(ZERO_NODE);
+ }
+
+ /**
+ * Обновление модели текущим символом
+ * @param value - очередной байт из исходной незакодированной последовательности
+ */
+ @Override
+ public void updateByCharacter(int value) {
+ CodeTreeNode node = nodeCache[((byte)value) & 0xff];
+ CodeTreeNode parent;
+ if (node != null) { // если уже есть узел для символа value
+ node.weight = node.weight + 1; // увеличим его вес на 1
+ parent = node.parent;
+ } else { // если узла нет, его надо создать
+ /*
+ создаем промежуточный узел, прикрепляем к нему escape символ и новый созданный узел для текущего символа
+ и вставляем промежуточный узел в дерево на старое место escape символа
+ */
+ CodeTreeNode zeroNodeParent = ZERO_NODE.parent;
+ CodeTreeNode newNode = new CodeTreeNode(value, 1, null, null, null);
+ CodeTreeNode intermediate = new CodeTreeNode(null, 0, ZERO_NODE, newNode, zeroNodeParent);
+ nodeCache[((byte)value) & 0xff] = newNode;
+ newNode.parent = intermediate;
+ if (zeroNodeParent != null) {
+ zeroNodeParent.left = intermediate;
+ } else {
+ tree = intermediate;
+ }
+ // добавляем новые узлы в список с учетом упорядоченности
+ nodeList.set(nodeList.size() - 1, intermediate);
+ nodeList.add(newNode);
+ nodeList.add(ZERO_NODE);
+
+ ZERO_NODE.parent = intermediate;
+
+ parent = newNode.parent;
+ }
+
+ // обновляем веса родительских узлов
+ while (parent != null) {
+ parent.weight = parent.weight + 1;
+ parent = parent.parent;
+ }
+
+ // восстанавливаем упорядоченность дерева, если она была нарушена в результате
+ // проделаных выше процедур по обновлению дерева
+ while (reorderNodes()) {
+ tree.updateWeights();
+ }
+ }
+
+ /**
+ * упорядочиваем дерево,
+ * переставляем узлы, нарушающие упорядоченность
+ * @return
+ */
+ private boolean reorderNodes() {
+ int i = 1;
+ for (; i < nodeList.size(); i++) { // ищем узел, нарушающий упорядоченность
+ if (nodeList.get(i - 1).weight < nodeList.get(i).weight) {
+ break;
+ }
+ }
+ if (i != nodeList.size()) {
+ CodeTreeNode first = nodeList.get(i);
+ int j = 0;
+ for (; j < i; j++) { // ищем узел, с которым надо поменять местами узел, нарушающий порядок
+ if (nodeList.get(j).weight < first.weight) {
+ break;
+ }
+ }
+ // меняем два узла в дереве местами для восстановления порядка
+ CodeTreeNode firstParent = first.parent;
+ CodeTreeNode second = nodeList.get(j);
+ if (first.parent == second.parent) {
+ if (first.weight < second.weight) {
+ firstParent.left = first;
+ firstParent.right = second;
+ } else {
+ firstParent.left = second;
+ firstParent.right = first;
+ }
+ } else {
+ if (second.parent != first) {
+ if (second.parent.left == second) {
+ second.parent.left = first;
+ } else {
+ second.parent.right = first;
+ }
+ first.parent = second.parent;
+ if (firstParent.left == first) {
+ firstParent.left = second;
+ } else {
+ firstParent.right = second;
+ }
+ second.parent = firstParent;
+ }
+ }
+
+ // меняем эти же два узла местами в списке
+ nodeList.set(j, first);
+ nodeList.set(i, second);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Метод выдает в выходной поток код символа
+ * @param value - символ, который надо закодировать
+ * @param bitWriter - приемник для битов символа
+ * @throws IOException
+ */
+ @Override
+ public void writeCodeForCharacter(Integer value, BitToByteWriter bitWriter) throws IOException {
+ CodeTreeNode node;
+ if (value != null) {
+ node = nodeCache[value.byteValue() & 0xff];
+ } else {
+ node = ZERO_NODE;
+ }
+ bitBuffer.setCurrent(0);
+ while (node.parent != null) { // идем от листа к корню дерева, собирая биты по пути
+ if (node.parent.left == node) {
+ bitBuffer.append(0);
+ } else {
+ bitBuffer.append(1);
+ }
+ node = node.parent;
+ }
+ for (int i = bitBuffer.current - 1; i >= 0 ; i--) { // выдаем биты кода, не забывая развернуть их в обратном порядке
+ bitWriter.writeBit(bitBuffer.get(i));
+ }
+ }
+
+ @Override
+ public CodeTreeNode getTree() {
+ return tree;
+ }
+
+ @Override
+ public CodeTreeNode getZeroNode() {
+ return ZERO_NODE;
+ }
+
+ @Override
+ public boolean contains(int value) {
+ return nodeCache[((byte)value) & 0xff] != null;
+ }
+
+}
diff --git a/src/ru/arhiser/huffman_adapt/digital/EncodingModelSimple.java b/src/ru/arhiser/huffman_adapt/digital/EncodingModelSimple.java
new file mode 100644
index 0000000..897785f
--- /dev/null
+++ b/src/ru/arhiser/huffman_adapt/digital/EncodingModelSimple.java
@@ -0,0 +1,84 @@
+package ru.arhiser.huffman_adapt.digital;
+
+import java.io.IOException;
+import java.util.*;
+
+public class EncodingModelSimple implements EncodingModel {
+
+ public final CodeTreeNode ZERO_NODE = new CodeTreeNode(null, 0);
+
+ private ArrayList nodeList = new ArrayList<>();
+ CodeTreeNode tree = ZERO_NODE;
+ HashMap nodeCache = new HashMap<>();
+ private BitBuffer bitBuffer = new BitBuffer(256);
+
+ @Override
+ public void updateByCharacter(int value) {
+ CodeTreeNode node = nodeCache.get(value);
+ if (node != null) {
+ node.weight += 1;
+ } else {
+ node = new CodeTreeNode(value, 1);
+ nodeCache.put(value, node);
+ }
+ buildHuffmanTree(nodeCache);
+ }
+
+ @Override
+ public void writeCodeForCharacter(Integer value, BitToByteWriter bitWriter) throws IOException {
+ CodeTreeNode node;
+ if (value != null) {
+ node = nodeCache.get(value);
+ } else {
+ node = ZERO_NODE;
+ }
+ bitBuffer.setCurrent(0);
+ while (node.parent != null) {
+ if (node.parent.left == node) {
+ bitBuffer.append(0);
+ } else {
+ bitBuffer.append(1);
+ }
+ node = node.parent;
+ }
+ for (int i = bitBuffer.current - 1; i >= 0 ; i--) {
+ bitWriter.writeBit(bitBuffer.get(i));
+ }
+ }
+
+ private CodeTreeNode buildHuffmanTree(Map nodeCache) {
+ nodeList.clear();
+
+ nodeList.addAll(nodeCache.values());
+
+ nodeList.add(ZERO_NODE);
+
+ while (nodeList.size() > 1) {
+ Collections.sort(nodeList);
+ CodeTreeNode left = nodeList.remove(nodeList.size() - 1);
+ CodeTreeNode right = nodeList.remove(nodeList.size() - 1);
+ CodeTreeNode parent = new CodeTreeNode(null, right.weight + left.weight, left, right, null);
+ left.parent = parent;
+ right.parent = parent;
+ nodeList.add(parent);
+ }
+
+ tree = nodeList.get(0);
+ return tree;
+ }
+
+ @Override
+ public CodeTreeNode getTree() {
+ return tree;
+ }
+
+ @Override
+ public CodeTreeNode getZeroNode() {
+ return ZERO_NODE;
+ }
+
+ @Override
+ public boolean contains(int value) {
+ return nodeCache.containsKey(value);
+ }
+}
diff --git a/src/ru/arhiser/huffman_adapt/digital/HuffmanDecoderStream.java b/src/ru/arhiser/huffman_adapt/digital/HuffmanDecoderStream.java
new file mode 100644
index 0000000..5ccfd7a
--- /dev/null
+++ b/src/ru/arhiser/huffman_adapt/digital/HuffmanDecoderStream.java
@@ -0,0 +1,83 @@
+package ru.arhiser.huffman_adapt.digital;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+
+/**
+ * Декодер.
+ * На вход подаем байты, сжатые адаптивным методом Хаффмана,
+ * на выходе в целевой поток outputStream получаем разархивированную информацию
+ */
+public class HuffmanDecoderStream extends OutputStream {
+
+ private static final int MODE_READ_UNENCODED_BYTE = 1;
+ private static final int MODE_READ_ENCODED_CHAR = 2;
+
+ private final EncodingModel encodingModel;
+ private final OutputStream outputStream;
+
+ private CodeTreeNode currentNode;
+
+ private final BitBuffer bitBuffer = new BitBuffer(8);
+
+ private int mode = MODE_READ_UNENCODED_BYTE;
+
+ public HuffmanDecoderStream(OutputStream outputStream) {
+ this.outputStream = outputStream;
+ encodingModel = new EncodingModelRefreshing();
+ }
+
+ public HuffmanDecoderStream(EncodingModel encodingModel, OutputStream outStream) {
+ this.outputStream = outStream;
+ this.encodingModel = encodingModel;
+ currentNode = encodingModel.getTree();
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ int mask = 1;
+ for (int i = 0; i < 8; i++) {
+ handleBit((b & mask) > 0 ? 1 : 0);
+ mask <<= 1;
+ }
+ }
+
+ /**
+ * Декодируем очередной бит
+ * @param bit - очередной бит из закодированной последовательности
+ * @throws IOException
+ */
+ private void handleBit(int bit) throws IOException {
+ if (mode == MODE_READ_UNENCODED_BYTE) { // если мы сейчас читаем незакодированный символ, то пишем бит в буфер, пока не накопится 8 бит
+ bitBuffer.append(bit);
+ if (bitBuffer.current == 8) { // если накопили 8 бит, то
+ encodingModel.updateByCharacter(bitBuffer.bytes[0]); // обновляем модель считанным незакодированным символом
+ outputStream.write(bitBuffer.bytes[0]); // выдаем символ на выход
+ bitBuffer.setCurrent(0);
+ mode = MODE_READ_ENCODED_CHAR; // переключаемся в режим чтения закодированного символа
+ currentNode = encodingModel.getTree();
+ }
+ } else { // если мы сейчас читаем закодированный символ
+ if (bit == 1) { // если бит == 1
+ currentNode = currentNode.right; // делаем шаг по дереву направо
+ } else {
+ currentNode = currentNode.left; // иначе делаем шаг по дереву налево
+ }
+ if (currentNode == encodingModel.getZeroNode()) { // если мы пришли в escape символ,
+ mode = MODE_READ_UNENCODED_BYTE; // переключаемся в режим чтения незакодированного символа
+ }
+ if (currentNode.content != null) { // если пришли в обычный узел
+ encodingModel.updateByCharacter(currentNode.content); // обновляем модель декодирванным символом
+ outputStream.write(currentNode.content); // выдаем декодированный символ на выход
+ currentNode = encodingModel.getTree(); // возвращаемся в начало дерева
+ }
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ outputStream.flush();
+ outputStream.close();
+ }
+}
diff --git a/src/ru/arhiser/huffman_adapt/digital/HuffmanEncoderStream.java b/src/ru/arhiser/huffman_adapt/digital/HuffmanEncoderStream.java
new file mode 100644
index 0000000..675d79c
--- /dev/null
+++ b/src/ru/arhiser/huffman_adapt/digital/HuffmanEncoderStream.java
@@ -0,0 +1,43 @@
+package ru.arhiser.huffman_adapt.digital;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+
+/**
+ * Кодировщик, осуществляющий сжатие информации адаптивным методом Хаффмана.
+ * На вход подаем байты, которые надо сжать, на выходе в outputStream получаем сжатую информацию
+ */
+public class HuffmanEncoderStream extends OutputStream {
+
+ EncodingModel encodingModel;
+
+ BitToByteWriter bitWriter;
+
+ public HuffmanEncoderStream(OutputStream outputStream) {
+ this.encodingModel = new EncodingModelRefreshing();
+ bitWriter = new BitToByteWriter(outputStream);
+ }
+
+ public HuffmanEncoderStream(EncodingModel encodingModel, OutputStream outStream) {
+ this.encodingModel = encodingModel;
+ bitWriter = new BitToByteWriter(outStream);
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ if (encodingModel.contains(b)) { // если символ уже есть в модели
+ encodingModel.writeCodeForCharacter(b, bitWriter); // выдаем на выход код этого символа
+ } else { // если символа еще нет,
+ encodingModel.writeCodeForCharacter(null, bitWriter); // выдаем escape-символ в выходной поток
+ bitWriter.writeByte(b); // выдаем незакодированный символ в выходной поток
+ }
+ encodingModel.updateByCharacter(b); // обновляем модель текущим символом
+ }
+
+ @Override
+ public void close() throws IOException {
+ encodingModel.writeCodeForCharacter(null, bitWriter);
+ bitWriter.close();
+ }
+}
diff --git a/src/ru/arhiser/huffman_adapt/digital/TestMain.java b/src/ru/arhiser/huffman_adapt/digital/TestMain.java
new file mode 100644
index 0000000..052e10d
--- /dev/null
+++ b/src/ru/arhiser/huffman_adapt/digital/TestMain.java
@@ -0,0 +1,104 @@
+package ru.arhiser.huffman_adapt.digital;
+
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+public class TestMain {
+ public static void main(String[] args) {
+ // codecTest();
+ //fileCodecTest();
+ fileCodecDigitalTest();
+ //createTestFile();
+ }
+
+ /**
+ * проверка кодирования строки
+ */
+ private static void codecTest() {
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ HuffmanEncoderStream huffmanEncoderStream = new HuffmanEncoderStream(new EncodingModelRefreshing(), byteArrayOutputStream);
+
+ //String text = "aab";
+ String text = "On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse pains.";
+ try {
+ huffmanEncoderStream.write(text.getBytes(StandardCharsets.UTF_8));
+ huffmanEncoderStream.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ byte[] encoded = byteArrayOutputStream.toByteArray();
+ byteArrayOutputStream.reset();
+
+ HuffmanDecoderStream huffmanDecoderStream = new HuffmanDecoderStream(new EncodingModelRefreshing(), byteArrayOutputStream);
+ try {
+ for (int i = 0; i < encoded.length; i++) {
+ huffmanDecoderStream.write(encoded[i]);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ assert byteArrayOutputStream.toString().equals(text);
+ }
+
+ /**
+ * проверка кодирования файла
+ */
+ private static void fileCodecTest() {
+ try {
+ String content = new String(Files.readAllBytes(Paths.get(".\\src\\ru\\arhiser\\huffman\\voyna-i-mir-tom-1.txt")));
+ BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(".\\src\\ru\\arhiser\\huffman_adapt\\digital\\voyna-i-mir-tom-1.huf"));
+ HuffmanEncoderStream huffmanEncoderStream = new HuffmanEncoderStream(new EncodingModelRefreshing(), bufferedOutputStream);
+ huffmanEncoderStream.write(content.getBytes(StandardCharsets.UTF_8));
+ huffmanEncoderStream.close();
+
+ BufferedOutputStream decodeOutput = new BufferedOutputStream(new FileOutputStream(".\\src\\ru\\arhiser\\huffman_adapt\\digital\\decoded.txt"));
+ HuffmanDecoderStream huffmanDecoderStream = new HuffmanDecoderStream(new EncodingModelRefreshing(), decodeOutput);
+ BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(".\\src\\ru\\arhiser\\huffman_adapt\\digital\\voyna-i-mir-tom-1.huf"));
+ byte[] buffer = new byte[1024];
+ int readNum;
+ while ((readNum = inputStream.read(buffer)) > 0) {
+ huffmanDecoderStream.write(buffer, 0, readNum);
+ }
+ decodeOutput.close();
+ huffmanDecoderStream.close();
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * проверка кодирования файла с чтением через FileInputStream
+ */
+ private static void fileCodecDigitalTest() {
+ try {
+ BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(".\\src\\ru\\arhiser\\huffman_adapt\\digital\\voyna-i-mir-tom-1.huf"));
+ HuffmanEncoderStream huffmanEncoderStream = new HuffmanEncoderStream(new EncodingModelRefreshing(), bufferedOutputStream);
+
+ BufferedInputStream bis = new BufferedInputStream(new FileInputStream(".\\src\\ru\\arhiser\\huffman\\voyna-i-mir-tom-1.txt"));
+ byte[] buffer = new byte[2048];
+ int read;
+ while ((read = bis.read(buffer, 0, buffer.length)) > 0) {
+ huffmanEncoderStream.write(buffer, 0, read);
+ }
+ bis.close();
+ huffmanEncoderStream.close();
+
+ BufferedOutputStream decodeOutput = new BufferedOutputStream(new FileOutputStream(".\\src\\ru\\arhiser\\huffman_adapt\\digital\\decoded.txt"));
+ HuffmanDecoderStream huffmanDecoderStream = new HuffmanDecoderStream(new EncodingModelRefreshing(), decodeOutput);
+ BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(".\\src\\ru\\arhiser\\huffman_adapt\\digital\\voyna-i-mir-tom-1.huf"));
+ int readNum;
+ while ((readNum = inputStream.read(buffer)) != -1) {
+ huffmanDecoderStream.write(buffer, 0, readNum);
+ }
+ decodeOutput.close();
+ huffmanDecoderStream.close();
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/ru/arhiser/imageprocess2/Main.java b/src/ru/arhiser/imageprocess2/Main.java
new file mode 100644
index 0000000..2485cbf
--- /dev/null
+++ b/src/ru/arhiser/imageprocess2/Main.java
@@ -0,0 +1,109 @@
+package ru.arhiser.imageprocess2;
+
+import javax.imageio.ImageIO;
+import javax.swing.*;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferByte;
+import java.awt.image.DataBufferInt;
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Исходники для видео: https://youtu.be/WG0mS-o1zSA
+ */
+public class Main {
+ /*
+ public static void main(String[] args) {
+
+ byte byteVal = (byte) 251;
+ System.out.println(byteVal);
+
+ int intVal = byteVal;
+ System.out.println(intVal);
+
+ intVal = 0xff & byteVal;
+ System.out.println(intVal);
+
+ System.out.println((byte) 128);
+
+ System.out.println(negative((byte) 15));
+
+ byte b1 = 5;
+ byte b2 = 7;
+ System.out.println(b1 - b2);
+ System.out.println(b1 + ~b2 + 1);
+
+ byte b3 = 100;
+ byte b4 = 100;
+ byte b5 = (byte) (b3 + b4);
+ System.out.println(b5);
+ }
+
+ static byte negative(byte value) {
+ return (byte) (256 - value);
+ }
+
+ static byte negative2(byte value) {
+ return (byte) (~value + 1);
+ }
+
+}
+ */
+
+
+ public static void main(String[] args) throws IOException {
+ JFrame frame = new JFrame();
+ frame.setSize(1200, 800);
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+
+
+ BufferedImage myPicture = ImageIO.read(new File(".\\src\\ru\\arhiser\\imageprocess2\\photo_3.jpg"));
+
+ Image scaled = myPicture.getScaledInstance(1200, 800, Image.SCALE_AREA_AVERAGING);
+
+ BufferedImage scaledImage = toBufferedImage(scaled);
+
+ JLabel picLabel = new JLabel(new ImageIcon(toGray(scaledImage)));
+
+ BorderLayout borderLayout = new BorderLayout();
+ frame.getContentPane().setLayout(borderLayout);
+ frame.getContentPane().add(picLabel, BorderLayout.CENTER);
+
+ frame.setVisible(true);
+ }
+
+ public static BufferedImage toGray(BufferedImage source) {
+ BufferedImage grayImage = new BufferedImage(source.getWidth(), source.getHeight(),
+ BufferedImage.TYPE_BYTE_GRAY);
+
+ byte[] outBuffer = ((DataBufferByte)grayImage.getRaster().getDataBuffer()).getData();
+ int[] inBuffer = ((DataBufferInt)source.getRaster().getDataBuffer()).getData();
+
+ for (int i = 0; i < source.getWidth() * grayImage.getHeight(); i++) {
+ int color = inBuffer[i];
+ int r = color >> 16 & 0xff;
+ int g = color >> 8 & 0xff;
+ int b = color & 0xff;
+ int gray = (r + g + b) / 3;
+ outBuffer[i] = (byte) gray;
+ }
+ return grayImage;
+ }
+
+ public static BufferedImage toBufferedImage(Image img) {
+ if (img instanceof BufferedImage) {
+ return (BufferedImage) img;
+ }
+ BufferedImage bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
+ Graphics2D bGr = bimage.createGraphics();
+ bGr.drawImage(img, 0, 0, null);
+ bGr.dispose();
+
+ return bimage;
+ }
+
+
+}
+
diff --git a/src/ru/arhiser/imageprocess2/photo_3.jpg b/src/ru/arhiser/imageprocess2/photo_3.jpg
new file mode 100644
index 0000000..4366d8a
Binary files /dev/null and b/src/ru/arhiser/imageprocess2/photo_3.jpg differ
diff --git a/src/ru/arhiser/iterator/MainDelete.java b/src/ru/arhiser/iterator/MainDelete.java
new file mode 100644
index 0000000..35640a7
--- /dev/null
+++ b/src/ru/arhiser/iterator/MainDelete.java
@@ -0,0 +1,21 @@
+package ru.arhiser.iterator;
+
+import java.util.LinkedList;
+import java.util.ListIterator;
+
+public class MainDelete {
+
+ public static void main(String[] args) {
+ LinkedList list = getRandomList();
+
+ list.removeIf(item -> item >= 128);
+ }
+
+ public static LinkedList getRandomList() {
+ LinkedList list = new LinkedList<>();
+ for (int i = 0; i < 100000; i++) {
+ list.add((int) Math.round(Math.random() * 256));
+ }
+ return list;
+ }
+}
diff --git a/src/ru/arhiser/iterator/MainFieldEnum.java b/src/ru/arhiser/iterator/MainFieldEnum.java
new file mode 100644
index 0000000..2faaad0
--- /dev/null
+++ b/src/ru/arhiser/iterator/MainFieldEnum.java
@@ -0,0 +1,27 @@
+package ru.arhiser.iterator;
+
+import ru.arhiser.object.Field;
+import ru.arhiser.object.FieldEnumerator;
+
+public class MainFieldEnum {
+
+ static class Contact {
+ int id;
+ String name;
+ String phone;
+
+ public Contact(int id, String name, String phone) {
+ this.id = id;
+ this.name = name;
+ this.phone = phone;
+ }
+ }
+
+ public static void main(String[] args) {
+ Contact contact = new Contact(123, "Вася Пупкин", "+129381832");
+
+ for(Field field: new FieldEnumerator(contact)) {
+ System.out.println(field);
+ }
+ }
+}
diff --git a/src/ru/arhiser/iterator/MainIteration.java b/src/ru/arhiser/iterator/MainIteration.java
new file mode 100644
index 0000000..94d0a5f
--- /dev/null
+++ b/src/ru/arhiser/iterator/MainIteration.java
@@ -0,0 +1,29 @@
+package ru.arhiser.iterator;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+
+public class MainIteration {
+ public static void main(String[] args) {
+
+ Integer[] array = new Integer[] {64, 42, 73, 41, 32, 53, 16, 24, 57, 42, 74, 55, 36};
+
+ ArrayList list = new ArrayList<>();
+
+ Collections.addAll(list, array);
+
+ for (int i = 0; i < list.size(); i++) {
+ System.out.println(list.get(i));
+ }
+
+ Iterator iterator = list.iterator();
+ while (iterator.hasNext()) {
+ System.out.println(iterator.next());
+ }
+
+ for (Integer integer: list) {
+ System.out.println(integer);
+ }
+ }
+}
diff --git a/src/ru/arhiser/iterator/MainRange.java b/src/ru/arhiser/iterator/MainRange.java
new file mode 100644
index 0000000..d7603dc
--- /dev/null
+++ b/src/ru/arhiser/iterator/MainRange.java
@@ -0,0 +1,48 @@
+package ru.arhiser.iterator;
+
+public class MainRange {
+ public static void main(String[] args) {
+ for(int i : Range.fromTo(0, 100)) {
+ System.out.println(i);
+ }
+ }
+
+ private static class Range implements Iterable {
+
+ int start;
+ int end;
+
+ public static Range fromTo(int from, int to) {
+ return new Range(from, to);
+ }
+
+ private Range(int start, int end) {
+ this.start = start;
+ this.end = end;
+ }
+
+ @Override
+ public Iterator iterator() {
+ return new Iterator(start);
+ }
+
+ class Iterator implements java.util.Iterator {
+
+ int current;
+
+ public Iterator(int current) {
+ this.current = current;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return current <= end;
+ }
+
+ @Override
+ public Integer next() {
+ return current++;
+ }
+ }
+ }
+}
diff --git a/src/ru/arhiser/iterator/MainSort.java b/src/ru/arhiser/iterator/MainSort.java
new file mode 100644
index 0000000..9e40503
--- /dev/null
+++ b/src/ru/arhiser/iterator/MainSort.java
@@ -0,0 +1,92 @@
+package ru.arhiser.iterator;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+
+public class MainSort {
+
+ public static void main(String[] args) {
+
+ ArrayList arrayListTest1 = new ArrayList<>();
+ fillListWithRandoms(arrayListTest1);
+ ArrayList arrayListTest2 = new ArrayList<>(arrayListTest1);
+
+ LinkedList linkedListTest1 = new LinkedList<>(arrayListTest1);
+ LinkedList linkedListTest2 = new LinkedList<>(arrayListTest1);
+
+ System.out.println("Array list naive");
+ measureTime(() -> {
+ sortNaive(arrayListTest1);
+ });
+ System.out.println("Array list iterator");
+ measureTime(() -> {
+ sortListIterator(arrayListTest2);
+ });
+ System.out.println("Linked list naive");
+ measureTime(() -> {
+ sortNaive(linkedListTest1);
+ });
+ System.out.println("Linked list iterator");
+ measureTime(() -> {
+ sortListIterator(linkedListTest2);
+ });
+ }
+
+ private static void sortNaive(List list) {
+ for (int i = 0; i < list.size(); i++) {
+ int current = list.get(i);
+ int min = current;
+ int minIndex = i;
+
+ for (int j = i; j < list.size(); j++) {
+ if (list.get(j) < min) {
+ min = list.get(j);
+ minIndex = j;
+ }
+ }
+
+ list.set(i, min);
+ list.set(minIndex, current);
+ }
+ }
+
+ private static void sortListIterator(List list) {
+ ListIterator iterator = list.listIterator();
+ while (iterator.hasNext()) {
+ ListIterator minimal = getMinIterator(list, list.listIterator(iterator.nextIndex()));
+ int current = iterator.next();
+ iterator.set(minimal.next());
+ minimal.set(current);
+ }
+ }
+
+ private static ListIterator getMinIterator(List list, ListIterator iterator) {
+ ListIterator minPosition = list.listIterator(iterator.nextIndex());
+ int min = iterator.next();
+ while (iterator.hasNext()) {
+ int current = iterator.next();
+ if (current < min) {
+ min = current;
+ while (minPosition.nextIndex() < iterator.nextIndex() - 1) {
+ minPosition.next();
+ }
+ }
+ }
+ return minPosition;
+ }
+
+ public static void fillListWithRandoms(List list) {
+ for (int i = 0; i < 5000; i++) {
+ list.add((int) Math.round(Math.random() * 256));
+ }
+ }
+
+ public static void measureTime(Runnable task) {
+ long startTime = System.currentTimeMillis();
+ task.run();
+ long elapsed = System.currentTimeMillis() - startTime;
+ System.out.println("Затраченное время: " + elapsed + " ms");
+ }
+}
diff --git a/src/ru/arhiser/knapsack/MainBruteforce.java b/src/ru/arhiser/knapsack/MainBruteforce.java
new file mode 100644
index 0000000..9eaa936
--- /dev/null
+++ b/src/ru/arhiser/knapsack/MainBruteforce.java
@@ -0,0 +1,59 @@
+package ru.arhiser.knapsack;
+
+public class MainBruteforce {
+ public static void main(String[] args) {
+ int[] weights = {3, 4, 5, 8, 9};
+ int[] prices = {1, 6, 4, 7, 6};
+
+ int maxWeight = 13;
+
+ long count = 2L << weights.length;
+
+ int maxPrice = 0;
+ long maxState = 0;
+
+ for (long state = 0; state < count; state++) {
+ int price = statePrice(state, prices);
+ int weight = stateWeight(state, weights);
+ if (weight <= maxWeight) {
+ if (maxPrice < price) {
+ maxPrice = price;
+ maxState = state;
+ }
+ }
+ }
+
+ System.out.println("Оптимальное содержимое рюкзака:");
+ long poverOfTwo = 1;
+ for (int i = 0; i < weights.length; i++) {
+ if ((poverOfTwo & maxState) > 0) {
+ System.out.println(i + 1);
+ }
+ poverOfTwo <<= 1;
+ }
+ }
+
+ private static int stateWeight(long state, int[] weights) {
+ long poverOfTwo = 1;
+ int weight = 0;
+ for (int i = 0; i < weights.length; i++) {
+ if ((poverOfTwo & state) != 0) {
+ weight += weights[i];
+ }
+ poverOfTwo <<= 1;
+ }
+ return weight;
+ }
+
+ private static int statePrice(long state, int[] prices) {
+ long poverOfTwo = 1;
+ int price = 0;
+ for (int i = 0; i < prices.length; i++) {
+ if ((poverOfTwo & state) != 0) {
+ price += prices[i];
+ }
+ poverOfTwo <<= 1;
+ }
+ return price;
+ }
+}
diff --git a/src/ru/arhiser/knapsack/MainDynamic.java b/src/ru/arhiser/knapsack/MainDynamic.java
new file mode 100644
index 0000000..96e09d2
--- /dev/null
+++ b/src/ru/arhiser/knapsack/MainDynamic.java
@@ -0,0 +1,54 @@
+package ru.arhiser.knapsack;
+
+import java.util.ArrayList;
+
+public class MainDynamic {
+
+ public static void main(String[] args) {
+ int[] weights = {3, 4, 5, 8, 9};
+ int[] prices = {1, 6, 4, 7, 6};
+
+ int count = weights.length;
+ int maxWeight = 13;
+
+ int[][] A;
+ A = new int[count + 1][];
+ for (int i = 0; i < count + 1; i++) {
+ A[i] = new int[maxWeight + 1];
+ }
+
+ for (int k = 0; k <= count; k++) {
+ for (int s = 0; s <= maxWeight; s++) {
+ if (k == 0 || s == 0) {
+ A[k][s] = 0;
+ } else {
+ if (s >= weights[k - 1]) {
+ A[k][s] = Math.max(A[k - 1][s], A[k - 1][s - weights[k - 1]] + prices[k - 1]);
+ } else {
+ A[k][s] = A[k - 1][s];
+ }
+ }
+ }
+ }
+
+ ArrayList result = new ArrayList<>();
+ traceResult(A, weights, count, maxWeight, result);
+
+ System.out.println("Оптимальное содержимое рюкзака:");
+ for(Integer integer : result) {
+ System.out.println(integer);
+ }
+ }
+
+ private static void traceResult(int[][] A, int[] weight, int k, int s, ArrayList result) {
+ if (A[k][s] == 0) {
+ return;
+ }
+ if (A[k -1][s] == A[k][s]) {
+ traceResult(A, weight, k - 1, s, result);
+ } else {
+ traceResult(A, weight, k - 1, s - weight[k - 1], result);
+ result.add(0, k);
+ }
+ }
+}
diff --git a/src/ru/arhiser/knapsack/MainGreedy.java b/src/ru/arhiser/knapsack/MainGreedy.java
new file mode 100644
index 0000000..8529111
--- /dev/null
+++ b/src/ru/arhiser/knapsack/MainGreedy.java
@@ -0,0 +1,46 @@
+package ru.arhiser.knapsack;
+
+import java.util.ArrayList;
+
+public class MainGreedy {
+
+ public static void main(String[] args) {
+ int[] weights = {3, 4, 5, 8, 9};
+ int[] prices = {1, 6, 4, 7, 6};
+
+ int maxWeight = 13;
+
+ ArrayList indexes = new ArrayList<>();
+ ArrayList result = new ArrayList<>();
+ int resultWeight = 0;
+
+ for (int i = 0; i < weights.length; i++) {
+ indexes.add(i);
+ }
+
+ while (!indexes.isEmpty()) {
+ int maxValue = prices[indexes.get(0)];
+ int maxIndex = indexes.get(0);
+
+ for (int i = 1; i < indexes.size(); i++) {
+ if (maxValue < prices[indexes.get(i)]) {
+ maxValue = prices[indexes.get(i)];
+ maxIndex = indexes.get(i);
+ }
+ }
+
+ resultWeight += weights[maxIndex];
+ if (resultWeight > maxWeight) {
+ break;
+ }
+
+ result.add(maxIndex);
+ indexes.remove(maxIndex);
+ }
+
+ System.out.println("Оптимальное содержимое рюкзака:");
+ for (Integer integer : result) {
+ System.out.println(integer + 1);
+ }
+ }
+}
diff --git a/src/ru/arhiser/multithreading/deadlock/Deadlock.java b/src/ru/arhiser/multithreading/deadlock/Deadlock.java
new file mode 100644
index 0000000..1a5add6
--- /dev/null
+++ b/src/ru/arhiser/multithreading/deadlock/Deadlock.java
@@ -0,0 +1,38 @@
+package ru.arhiser.multithreading.deadlock;
+
+public class Deadlock {
+ public static void main(String[] args) {
+ Object lock1 = new Object();
+ Object lock2 = new Object();
+
+ Thread thread1 = new Thread(() -> {
+ System.out.println(Thread.currentThread().getName() + " start");
+ synchronized (lock1) {
+
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ synchronized (lock2) {
+
+ }
+ }
+ System.out.println(Thread.currentThread().getName() + " end");
+ }, "Thread1");
+
+ Thread thread2 = new Thread(() -> {
+ System.out.println(Thread.currentThread().getName() + " start");
+ synchronized (lock2) {
+ synchronized (lock1) {
+
+ }
+ }
+ System.out.println(Thread.currentThread().getName() + " end");
+ }, "Thread2");
+
+ thread1.start();
+ thread2.start();
+ }
+}
diff --git a/src/ru/arhiser/multithreading/deadlock/DeadlockComplex.java b/src/ru/arhiser/multithreading/deadlock/DeadlockComplex.java
new file mode 100644
index 0000000..6712521
--- /dev/null
+++ b/src/ru/arhiser/multithreading/deadlock/DeadlockComplex.java
@@ -0,0 +1,67 @@
+package ru.arhiser.multithreading.deadlock;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class DeadlockComplex {
+ public static void main(String[] args) {
+ ArrayList resources = new ArrayList<>();
+ for (int i = 0; i < 10; i++) {
+ resources.add(new Resource(i));
+ }
+
+ Comparator comparator = new Comparator() {
+ @Override
+ public int compare(Resource o1, Resource o2) {
+ return resources.indexOf(o1) - resources.indexOf(o2);
+ }
+ };
+
+ ExecutorService executorService = Executors.newFixedThreadPool(2);
+
+ executorService.execute(() -> handle(resources.get(0), resources.get(1), comparator));
+ executorService.execute(() -> handle(resources.get(1), resources.get(0), comparator));
+ }
+
+ public static void handle(Resource res1, Resource res2, Comparator comparator) {
+ Object lock1 = res1;
+ Object lock2 = res2;
+ if (comparator.compare(res1, res2) < 0) {
+ lock2 = res1;
+ lock1 = res2;
+ }
+
+ System.out.println(Thread.currentThread().getName() + " start");
+ synchronized (lock1) {
+
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ synchronized (lock2) {
+ res1.setValue(res2.getValue());
+ }
+ }
+ System.out.println(Thread.currentThread().getName() + " end");
+ }
+
+ static class Resource {
+ int value;
+
+ public Resource(int value) {
+ this.value = value;
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ public void setValue(int value) {
+ this.value = value;
+ }
+ }
+}
diff --git a/src/ru/arhiser/multithreading/parallel2/Main.java b/src/ru/arhiser/multithreading/parallel2/Main.java
new file mode 100644
index 0000000..9caade4
--- /dev/null
+++ b/src/ru/arhiser/multithreading/parallel2/Main.java
@@ -0,0 +1,89 @@
+package ru.arhiser.multithreading.parallel2;
+
+import ru.arhiser.Utils;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferInt;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import static java.awt.image.BufferedImage.TYPE_INT_RGB;
+
+public class Main {
+
+ public static void main(String[] args) throws IOException, InterruptedException {
+ BufferedImage picture = ImageIO.read(new File(".\\src\\ru\\arhiser\\multithreading\\parallel2\\photo_.jpg"));
+
+ picture = Utils.toBufferedImage(picture.getScaledInstance(3840, 2160, Image.SCALE_SMOOTH));
+
+ BufferedImage out = new BufferedImage(picture.getWidth(), picture.getHeight(), TYPE_INT_RGB);
+ int[] destPixels = ((DataBufferInt) out.getRaster().getDataBuffer()).getData();
+ int[] sourcePixels = ((DataBufferInt) picture.getRaster().getDataBuffer()).getData();
+
+ final int = 20;
+
+ ExecutorService executor = Executors.newFixedThreadPool(4);
+ ArrayList tasks = new ArrayList<>();
+ CountDownLatch latch = new CountDownLatch(4);
+
+ int portion = out.getHeight() / 4;
+ for (int p = 0; p < out.getHeight(); p += portion) {
+ int finalP = p;
+ tasks.add(new Runnable() {
+ @Override
+ public void run() {
+ for (int y = finalP; y < finalP + portion; y++) {
+ for (int x = 0; x < out.getWidth(); x++) {
+ destPixels[y* out.getWidth() + x] = getOutValue(sourcePixels, out.getWidth(), x, y, BLUR_SIZE);
+ }
+ }
+ latch.countDown();
+ }
+ });
+ }
+
+ Utils.measureTime(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ for (Runnable task: tasks) {
+ executor.submit(task);
+ }
+
+ latch.await();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }, "blur");
+
+
+ Utils.showImageWindow(out);
+ }
+
+ private static int getOutValue(int[] source, int line, int x, int y, int blurSize) {
+ int halfSize = blurSize / 2;
+ int count = 0;
+ int rsum = 0;
+ int gsum = 0;
+ int bsum = 0;
+ for (int i = y - halfSize; i <= y + halfSize; i++) {
+ for (int j = x - halfSize; j <= x + halfSize; j++) {
+ if (j >=0 && i >= 0 && j < line && (i < source.length / line)) {
+ count += 1;
+ rsum += (source[i * line + j] & 0xff0000) >> 16;
+ gsum += (source[i * line + j] & 0xff00) >> 8;
+ bsum += (source[i * line + j] & 0xff);
+ }
+ }
+ }
+ return 0xff000000 | ((rsum / count) << 16) | ((gsum / count) << 8) | (bsum / count);
+ }
+
+}
diff --git a/src/ru/arhiser/multithreading/parallel2/ParallelForkJoin.java b/src/ru/arhiser/multithreading/parallel2/ParallelForkJoin.java
new file mode 100644
index 0000000..889b1af
--- /dev/null
+++ b/src/ru/arhiser/multithreading/parallel2/ParallelForkJoin.java
@@ -0,0 +1,85 @@
+package ru.arhiser.multithreading.parallel2;
+
+import ru.arhiser.Utils;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferInt;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ForkJoinPool;
+
+import static java.awt.image.BufferedImage.TYPE_INT_RGB;
+
+public class ParallelForkJoin {
+
+ public static void main(String[] args) throws IOException {
+ BufferedImage picture = ImageIO.read(new File(".\\src\\ru\\arhiser\\multithreading\\parallel2\\photo_.jpg"));
+
+ picture = Utils.toBufferedImage(picture.getScaledInstance(3840, 2160, Image.SCALE_SMOOTH));
+
+ BufferedImage out = new BufferedImage(picture.getWidth(), picture.getHeight(), TYPE_INT_RGB);
+ int[] destPixels = ((DataBufferInt) out.getRaster().getDataBuffer()).getData();
+ int[] sourcePixels = ((DataBufferInt) picture.getRaster().getDataBuffer()).getData();
+
+ int taskCount = out.getWidth() * out.getHeight();
+
+ final int BLUR_SIZE = 4;
+
+ ExecutorService executor = Executors.newWorkStealingPool(4);
+ ArrayList tasks = new ArrayList<>();
+ CountDownLatch latch = new CountDownLatch(taskCount);
+
+ for (int y = 0; y < out.getHeight(); y++) {
+ for (int x = 0; x < out.getWidth(); x++) {
+ int finalY = y;
+ int finalX = x;
+ tasks.add(() -> {
+ destPixels[finalY * out.getWidth() + finalX] = getOutValue(sourcePixels, out.getWidth(), finalX, finalY, BLUR_SIZE);
+ latch.countDown();
+ });
+ }
+ }
+
+ long startTime = System.currentTimeMillis();
+
+ for(Runnable task: tasks) {
+ executor.submit(task);
+ }
+ try {
+ latch.await();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ long elapsed = System.currentTimeMillis() - startTime;
+ System.out.println("Elapsed time" + ": " + elapsed + " ms");
+
+ Utils.showImageWindow(out);
+ }
+
+ private static int getOutValue(int[] source, int line, int x, int y, int blurSize) {
+ int halfSize = blurSize / 2;
+ int count = 0;
+ int rsum = 0;
+ int gsum = 0;
+ int bsum = 0;
+ for (int i = y - halfSize; i <= y + halfSize; i++) {
+ for (int j = x - halfSize; j <= x + halfSize; j++) {
+ if (j >=0 && i >= 0 && j < line && (i < source.length / line)) {
+ count += 1;
+ rsum += (source[i * line + j] & 0xff0000) >> 16;
+ gsum += (source[i * line + j] & 0xff00) >> 8;
+ bsum += (source[i * line + j] & 0xff);
+ }
+ }
+ }
+ return 0xff000000 | ((rsum / count) << 16) | ((gsum / count) << 8) | (bsum / count);
+ }
+
+}
diff --git a/src/ru/arhiser/multithreading/parallel2/ParallelNaive.java b/src/ru/arhiser/multithreading/parallel2/ParallelNaive.java
new file mode 100644
index 0000000..d34afd9
--- /dev/null
+++ b/src/ru/arhiser/multithreading/parallel2/ParallelNaive.java
@@ -0,0 +1,85 @@
+package ru.arhiser.multithreading.parallel2;
+
+import ru.arhiser.Utils;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferInt;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import static java.awt.image.BufferedImage.TYPE_INT_RGB;
+
+public class ParallelNaive {
+
+ public static void main(String[] args) throws IOException {
+ BufferedImage picture = ImageIO.read(new File(".\\src\\ru\\arhiser\\multithreading\\parallel2\\photo_.jpg"));
+
+ picture = Utils.toBufferedImage(picture.getScaledInstance(3840, 2160, Image.SCALE_SMOOTH));
+
+ BufferedImage out = new BufferedImage(picture.getWidth(), picture.getHeight(), TYPE_INT_RGB);
+ int[] destPixels = ((DataBufferInt) out.getRaster().getDataBuffer()).getData();
+ int[] sourcePixels = ((DataBufferInt) picture.getRaster().getDataBuffer()).getData();
+
+ int taskCount = out.getWidth() * out.getHeight();
+
+ final int BLUR_SIZE = 20;
+
+ ExecutorService executor = Executors.newFixedThreadPool(4);
+ ArrayList tasks = new ArrayList<>();
+ CountDownLatch latch = new CountDownLatch(taskCount);
+
+ for (int y = 0; y < out.getHeight(); y++) {
+ for (int x = 0; x < out.getWidth(); x++) {
+ int finalY = y;
+ int finalX = x;
+ tasks.add(() -> {
+ destPixels[finalY * out.getWidth() + finalX] = getOutValue(sourcePixels, out.getWidth(), finalX, finalY, BLUR_SIZE);
+ latch.countDown();
+ });
+ }
+ }
+
+ long startTime = System.currentTimeMillis();
+
+ for(Runnable task: tasks) {
+ executor.submit(task);
+ }
+ try {
+ latch.await();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ long elapsed = System.currentTimeMillis() - startTime;
+ System.out.println("Elapsed time" + ": " + elapsed + " ms");
+
+ Utils.showImageWindow(out);
+ }
+
+ private static int getOutValue(int[] source, int line, int x, int y, int blurSize) {
+ int halfSize = blurSize / 2;
+ int count = 0;
+ int rsum = 0;
+ int gsum = 0;
+ int bsum = 0;
+ for (int i = y - halfSize; i <= y + halfSize; i++) {
+ for (int j = x - halfSize; j <= x + halfSize; j++) {
+ if (j >=0 && i >= 0 && j < line && (i < source.length / line)) {
+ count += 1;
+ rsum += (source[i * line + j] & 0xff0000) >> 16;
+ gsum += (source[i * line + j] & 0xff00) >> 8;
+ bsum += (source[i * line + j] & 0xff);
+ }
+ }
+ }
+ return 0xff000000 | ((rsum / count) << 16) | ((gsum / count) << 8) | (bsum / count);
+ }
+
+}
diff --git a/src/ru/arhiser/multithreading/parallel2/ParallelRight.java b/src/ru/arhiser/multithreading/parallel2/ParallelRight.java
new file mode 100644
index 0000000..bf80ddb
--- /dev/null
+++ b/src/ru/arhiser/multithreading/parallel2/ParallelRight.java
@@ -0,0 +1,84 @@
+package ru.arhiser.multithreading.parallel2;
+
+import ru.arhiser.Utils;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferInt;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import static java.awt.image.BufferedImage.TYPE_INT_RGB;
+
+public class ParallelRight {
+
+ public static void main(String[] args) throws IOException {
+ BufferedImage picture = ImageIO.read(new File(".\\src\\ru\\arhiser\\multithreading\\parallel2\\photo_.jpg"));
+
+ picture = Utils.toBufferedImage(picture.getScaledInstance(3840, 2160, Image.SCALE_SMOOTH));
+
+ BufferedImage out = new BufferedImage(picture.getWidth(), picture.getHeight(), TYPE_INT_RGB);
+ int[] destPixels = ((DataBufferInt) out.getRaster().getDataBuffer()).getData();
+ int[] sourcePixels = ((DataBufferInt) picture.getRaster().getDataBuffer()).getData();
+
+ final int BLUR_SIZE = 20;
+
+ ExecutorService executor = Executors.newFixedThreadPool(4);
+ ArrayList tasks = new ArrayList<>();
+ CountDownLatch latch = new CountDownLatch(4);
+
+ int portion = out.getHeight() / 4;
+ for (int p = 0; p < out.getHeight(); p += portion) {
+ int finalP = p;
+ tasks.add(() -> {
+ for (int y = finalP; y < finalP + portion; y++) {
+ for (int x = 0; x < out.getWidth(); x++) {
+ destPixels[y * out.getWidth() + x] = getOutValue(sourcePixels, out.getWidth(), x, y, BLUR_SIZE);
+ }
+ }
+ latch.countDown();
+ });
+ }
+
+ long startTime = System.currentTimeMillis();
+
+ for(Runnable task: tasks) {
+ executor.submit(task);
+ }
+ try {
+ latch.await();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ long elapsed = System.currentTimeMillis() - startTime;
+ System.out.println("Elapsed time" + ": " + elapsed + " ms");
+
+ Utils.showImageWindow(out);
+ }
+
+ private static int getOutValue(int[] source, int line, int x, int y, int blurSize) {
+ int halfSize = blurSize / 2;
+ int count = 0;
+ int rsum = 0;
+ int gsum = 0;
+ int bsum = 0;
+ for (int i = y - halfSize; i <= y + halfSize; i++) {
+ for (int j = x - halfSize; j <= x + halfSize; j++) {
+ if (j >=0 && i >= 0 && j < line && (i < source.length / line)) {
+ count += 1;
+ rsum += (source[i * line + j] & 0xff0000) >> 16;
+ gsum += (source[i * line + j] & 0xff00) >> 8;
+ bsum += (source[i * line + j] & 0xff);
+ }
+ }
+ }
+ return 0xff000000 | ((rsum / count) << 16) | ((gsum / count) << 8) | (bsum / count);
+ }
+
+}
diff --git a/src/ru/arhiser/multithreading/parallel2/Single.java b/src/ru/arhiser/multithreading/parallel2/Single.java
new file mode 100644
index 0000000..e2c1dbb
--- /dev/null
+++ b/src/ru/arhiser/multithreading/parallel2/Single.java
@@ -0,0 +1,60 @@
+package ru.arhiser.multithreading.parallel2;
+
+import ru.arhiser.Utils;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferInt;
+import java.io.File;
+import java.io.IOException;
+
+import static java.awt.image.BufferedImage.TYPE_INT_RGB;
+
+public class Single {
+
+ public static void main(String[] args) throws IOException {
+ BufferedImage picture = ImageIO.read(new File(".\\src\\ru\\arhiser\\multithreading\\parallel2\\photo_.jpg"));
+
+ picture = Utils.toBufferedImage(picture.getScaledInstance(3840, 2160, Image.SCALE_SMOOTH));
+
+ BufferedImage out = new BufferedImage(picture.getWidth(), picture.getHeight(), TYPE_INT_RGB);
+ int[] destPixels = ((DataBufferInt) out.getRaster().getDataBuffer()).getData();
+ int[] sourcePixels = ((DataBufferInt) picture.getRaster().getDataBuffer()).getData();
+
+ final int BLUR_SIZE = 4;
+
+ Utils.measureTime(new Runnable() {
+ @Override
+ public void run() {
+ for (int y = 0; y < out.getHeight(); y++) {
+ for (int x = 0; x < out.getWidth(); x++) {
+ destPixels[y * out.getWidth() + x] = getOutValue(sourcePixels, out.getWidth(), x, y, BLUR_SIZE);
+ }
+ }
+ }
+ }, "blur");
+
+ Utils.showImageWindow(out);
+ }
+
+ private static int getOutValue(int[] source, int line, int x, int y, int blurSize) {
+ int halfSize = blurSize / 2;
+ int count = 0;
+ int rsum = 0;
+ int gsum = 0;
+ int bsum = 0;
+ for (int i = y - halfSize; i <= y + halfSize; i++) {
+ for (int j = x - halfSize; j <= x + halfSize; j++) {
+ if (j >=0 && i >= 0 && j < line && (i < source.length / line)) {
+ count += 1;
+ rsum += (source[i * line + j] & 0xff0000) >> 16;
+ gsum += (source[i * line + j] & 0xff00) >> 8;
+ bsum += (source[i * line + j] & 0xff);
+ }
+ }
+ }
+ return 0xff000000 | ((rsum / count) << 16) | ((gsum / count) << 8) | (bsum / count);
+ }
+
+}
diff --git a/src/ru/arhiser/multithreading/parallel2/photo_.jpg b/src/ru/arhiser/multithreading/parallel2/photo_.jpg
new file mode 100644
index 0000000..290aeab
Binary files /dev/null and b/src/ru/arhiser/multithreading/parallel2/photo_.jpg differ
diff --git a/src/ru/arhiser/multithreading/stop/Main.java b/src/ru/arhiser/multithreading/stop/Main.java
new file mode 100644
index 0000000..eabc72e
--- /dev/null
+++ b/src/ru/arhiser/multithreading/stop/Main.java
@@ -0,0 +1,71 @@
+package ru.arhiser.multithreading.stop;
+
+import java.util.ArrayList;
+
+public class Main {
+
+ public static void main(String[] args) {
+
+ BlockingQueue queue = new BlockingQueue();
+
+ Thread worker = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ while (!Thread.currentThread().isInterrupted()) {
+ Runnable task = null;
+ try {
+ task = queue.get();
+ task.run();
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+ });
+ worker.start();
+
+ for (int i = 0; i < 5; i++) {
+ queue.put(getTask());
+ }
+
+ try {
+ Thread.sleep(3000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ worker.interrupt();
+ }
+
+ static class BlockingQueue {
+ ArrayList tasks = new ArrayList<>();
+
+ public synchronized Runnable get() throws InterruptedException {
+ while (tasks.isEmpty()) {
+ wait();
+ }
+ Runnable task = tasks.get(0);
+ tasks.remove(task);
+ return task;
+ }
+
+ public synchronized void put(Runnable task) {
+ tasks.add(task);
+ notify();
+ }
+ }
+
+ public static Runnable getTask() {
+ return new Runnable() {
+ @Override
+ public void run() {
+ System.out.println("Task started: " + this);
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ System.out.println("Task finished: " + this);
+ }
+ };
+ }
+}
diff --git a/src/ru/arhiser/prefix_tree/Main.java b/src/ru/arhiser/prefix_tree/Main.java
new file mode 100644
index 0000000..05b46c0
--- /dev/null
+++ b/src/ru/arhiser/prefix_tree/Main.java
@@ -0,0 +1,135 @@
+package ru.arhiser.prefix_tree;
+
+import java.io.*;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+public class Main {
+ public static void main(String[] params) throws IOException {
+ List lines = Files.readAllLines(Paths.get(".\\src\\ru\\arhiser\\prefix_tree\\numbers.txt"));
+
+ TreeNode root = new TreeNode(' ');
+ for (String line: lines) {
+ root.insert(line);
+ }
+
+ //System.out.println(root.containString("18АА0603"));
+
+ writeTreeToFile(".\\src\\ru\\arhiser\\prefix_tree\\tree.dat", root);
+
+ TreeNode fromFile = readFromFile(".\\src\\ru\\arhiser\\prefix_tree\\tree.dat");
+
+ List extractedFromTree = new ArrayList<>();
+ fromFile.getAllNumbers("", extractedFromTree);
+ }
+
+ static class TreeNode {
+ char value;
+ List children;
+
+ public TreeNode(char value) {
+ this.value = value;
+ }
+
+ public void insert(String data) {
+ if (data.length() == 0) {
+ return;
+ }
+ if (children == null) {
+ children = new ArrayList<>();
+ }
+ char c = data.charAt(0);
+ TreeNode child = findNodeByChar(c);
+ if (child == null) {
+ child = new TreeNode(c);
+ children.add(child);
+ }
+ child.insert(data.substring(1));
+ }
+
+ private TreeNode findNodeByChar(char c) {
+ if (children != null) {
+ for(TreeNode node: children) {
+ if (node.value == c) {
+ return node;
+ }
+ }
+ }
+ return null;
+ }
+
+ private boolean containString(String str) {
+ TreeNode current = this;
+ for (int i = 0; i < str.length(); i++) {
+ current = current.findNodeByChar(str.charAt(i));
+ if (current == null) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public void getAllNumbers(String path, List result) {
+ if (value != ' ') {
+ path = path + value;
+ }
+ if (children != null) {
+ for(TreeNode node: children) {
+ node.getAllNumbers(path, result);
+ }
+ } else {
+ result.add(path);
+ }
+ }
+
+ public void writeToFile(PrintWriter writer) {
+ writer.write(value);
+ if (children != null) {
+ for (TreeNode node: children) {
+ node.writeToFile(writer);
+ }
+ }
+ writer.write(']');
+ }
+
+ public void readFromFile(FileReader reader) throws IOException {
+ char ch;
+ while ((ch = (char)reader.read()) != ']') {
+ TreeNode treeNode = new TreeNode(ch);
+ treeNode.readFromFile(reader);
+ if (children == null) {
+ children = new ArrayList<>();
+ }
+ children.add(treeNode);
+ }
+ }
+ }
+
+ public static void writeTreeToFile(String path, TreeNode root) {
+ try {
+ PrintWriter out = new PrintWriter(path);
+ root.writeToFile(out);
+ out.flush();
+ out.close();
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static TreeNode readFromFile(String path) {
+ TreeNode root = new TreeNode(' ');
+ try {
+ FileReader reader = new FileReader(path);
+ reader.read();
+ root.readFromFile(reader);
+ reader.close();
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return root;
+ }
+}
diff --git a/src/ru/arhiser/prefix_tree/numbers.txt b/src/ru/arhiser/prefix_tree/numbers.txt
new file mode 100644
index 0000000..b649641
--- /dev/null
+++ b/src/ru/arhiser/prefix_tree/numbers.txt
@@ -0,0 +1,66 @@
+18АА0597
+18АА0598
+18АА0599
+18АА0600
+18АА0601
+18АА0602
+18АА0603
+18АА0604
+18АА0605
+18АО6634
+18АО6896
+18АО6897
+18АО6898
+18АО6899
+18АО6900
+18АО7321
+18АО7510
+18АО7511
+18АО7512
+18АР0310
+18АР0311
+18АР0312
+18АР0313
+18АР0314
+18АР0315
+18АР0316
+18АР2960
+18АР2961
+18АР2962
+18АР2963
+18АР2964
+18АР2965
+18АР2966
+18АР2967
+18АР2968
+18АР2969
+18АР2970
+18АР2971
+18АР2972
+18АР2973
+18АР2974
+18АР2975
+18АТ0468
+18АТ0469
+18АТ0470
+18АТ0471
+18АТ0472
+18АТ0473
+18АТ0474
+18АТ0475
+18АТ0476
+18АТ0477
+18АТ0478
+18АТ0479
+18АТ0480
+18АТ0481
+18АТ0482
+18АТ0483
+18АХ0365
+18АХ0366
+18АХ0367
+18АХ0368
+18АХ0369
+18АХ0370
+18АХ0371
+18АХ0372
\ No newline at end of file
diff --git a/src/ru/arhiser/prefix_tree/tree.dat b/src/ru/arhiser/prefix_tree/tree.dat
new file mode 100644
index 0000000..369a36c
--- /dev/null
+++ b/src/ru/arhiser/prefix_tree/tree.dat
@@ -0,0 +1 @@
+ 18АА0597]8]9]]]600]1]2]3]4]5]]]]]О6634]]]896]7]8]9]]]900]]]]7321]]]510]1]2]]]]]Р0310]1]2]3]4]5]6]]]]2960]1]2]3]4]5]6]7]8]9]]70]1]2]3]4]5]]]]]Т0468]9]]70]1]2]3]4]5]6]7]8]9]]80]1]2]3]]]]]Х0365]6]7]8]9]]70]1]2]]]]]]]]]
\ No newline at end of file
diff --git a/src/ru/arhiser/prefix_tree/tree_formatted.dat b/src/ru/arhiser/prefix_tree/tree_formatted.dat
new file mode 100644
index 0000000..bb82a18
--- /dev/null
+++ b/src/ru/arhiser/prefix_tree/tree_formatted.dat
@@ -0,0 +1,217 @@
+
+
+ 1
+ 8
+ А
+ А
+ 0
+ 5
+ 9
+ 7
+ ]
+ 8
+ ]
+ 9
+ ]
+ ]
+ ]
+ 6
+ 0
+ 0
+ ]
+ 1
+ ]
+ 2
+ ]
+ 3
+ ]
+ 4
+ ]
+ 5
+ ]
+ ]
+ ]
+ ]
+ ]
+ О
+ 6
+ 6
+ 3
+ 4
+ ]
+ ]
+ ]
+ 8
+ 9
+ 6
+ ]
+ 7
+ ]
+ 8
+ ]
+ 9
+ ]
+ ]
+ ]
+ 9
+ 0
+ 0
+ ]
+ ]
+ ]
+ ]
+ 7
+ 3
+ 2
+ 1
+ ]
+ ]
+ ]
+ 5
+ 1
+ 0
+ ]
+ 1
+ ]
+ 2
+ ]
+ ]
+ ]
+ ]
+ ]
+ Р
+ 0
+ 3
+ 1
+ 0
+ ]
+ 1
+ ]
+ 2
+ ]
+ 3
+ ]
+ 4
+ ]
+ 5
+ ]
+ 6
+ ]
+ ]
+ ]
+ ]
+ 2
+ 9
+ 6
+ 0
+ ]
+ 1
+ ]
+ 2
+ ]
+ 3
+ ]
+ 4
+ ]
+ 5
+ ]
+ 6
+ ]
+ 7
+ ]
+ 8
+ ]
+ 9
+ ]
+ ]
+ 7
+ 0
+ ]
+ 1
+ ]
+ 2
+ ]
+ 3
+ ]
+ 4
+ ]
+ 5
+ ]
+ ]
+ ]
+ ]
+ ]
+ Т
+ 0
+ 4
+ 6
+ 8
+ ]
+ 9
+ ]
+ ]
+ 7
+ 0
+ ]
+ 1
+ ]
+ 2
+ ]
+ 3
+ ]
+ 4
+ ]
+ 5
+ ]
+ 6
+ ]
+ 7
+ ]
+ 8
+ ]
+ 9
+ ]
+ ]
+ 8
+ 0
+ ]
+ 1
+ ]
+ 2
+ ]
+ 3
+ ]
+ ]
+ ]
+ ]
+ ]
+ Х
+ 0
+ 3
+ 6
+ 5
+ ]
+ 6
+ ]
+ 7
+ ]
+ 8
+ ]
+ 9
+ ]
+ ]
+ 7
+ 0
+ ]
+ 1
+ ]
+ 2
+ ]
+ ]
+ ]
+ ]
+ ]
+ ]
+ ]
+ ]
+]
\ No newline at end of file
diff --git a/src/ru/arhiser/rxjava/Main1.java b/src/ru/arhiser/rxjava/Main1.java
new file mode 100644
index 0000000..4f246da
--- /dev/null
+++ b/src/ru/arhiser/rxjava/Main1.java
@@ -0,0 +1,58 @@
+package ru.arhiser.rxjava;
+
+import io.reactivex.rxjava3.annotations.NonNull;
+import io.reactivex.rxjava3.core.BackpressureStrategy;
+import io.reactivex.rxjava3.core.Flowable;
+import io.reactivex.rxjava3.core.FlowableEmitter;
+import io.reactivex.rxjava3.core.FlowableOnSubscribe;
+import io.reactivex.rxjava3.schedulers.Schedulers;
+import ru.arhiser.funcops.Client;
+
+import java.util.ArrayList;
+
+public class Main1 {
+ public static void main(String[] args) {
+ ArrayList clients = new ArrayList<>();
+
+ clients.add(new Client("Harry Carter", 15, true));
+ clients.add(new Client("Adam Atkinson", 5, true));
+ clients.add(new Client("Bobby Robertson", 8, true));
+ clients.add(new Client("Liam Ellis", 6, false));
+ clients.add(new Client("Alex Thomson", 9, true));
+ clients.add(new Client("Ryan Ayala", 4, false));
+ clients.add(new Client("Kale Molina", 3, true));
+ clients.add(new Client("Otto Holman", 7, false));
+
+ clients.stream()
+ .filter(Client::isActive)
+ .map(Client::getName)
+ .forEach(System.out::println);
+
+ System.out.println("111111111111111");
+
+ Flowable clientFlowable = Flowable.create(new FlowableOnSubscribe() {
+ @Override
+ public void subscribe(@NonNull FlowableEmitter emitter) throws Throwable { // subscribeOn
+ for (Client c: clients) {
+ emitter.onNext(c);
+ }
+ emitter.onComplete();
+ }
+ }, BackpressureStrategy.BUFFER);
+
+ clientFlowable
+ .observeOn(Schedulers.computation())
+ .subscribeOn(Schedulers.io())
+ .filter(Client::isActive) // observeOn
+ .map(Client::getName)
+ .forEach(System.out::println);
+
+ System.out.println("2222222222222222");
+
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/ru/arhiser/rxjava/Main2.java b/src/ru/arhiser/rxjava/Main2.java
new file mode 100644
index 0000000..dc87c7e
--- /dev/null
+++ b/src/ru/arhiser/rxjava/Main2.java
@@ -0,0 +1,55 @@
+package ru.arhiser.rxjava;
+
+import io.reactivex.rxjava3.annotations.NonNull;
+import io.reactivex.rxjava3.core.*;
+import io.reactivex.rxjava3.disposables.Disposable;
+import io.reactivex.rxjava3.functions.Consumer;
+import ru.arhiser.Utils;
+import ru.arhiser.funcops.Client;
+
+import javax.swing.*;
+import java.awt.*;
+import java.util.Date;
+import java.util.Timer;
+import java.util.TimerTask;
+
+public class Main2 {
+ public static void main(String[] args) {
+ Observable timeObservable = Observable.create(new ObservableOnSubscribe() {
+ @Override
+ public void subscribe(@NonNull ObservableEmitter emitter) throws Throwable {
+ Timer timer = new Timer();
+ timer.scheduleAtFixedRate(new TimerTask() {
+ @Override
+ public void run() {
+ emitter.onNext(new Date());
+ }
+ }, 0, 1000);
+ }
+ });
+
+ timeObservable.subscribe(new Consumer() {
+ @Override
+ public void accept(Date date) throws Throwable {
+ System.out.println(date.toString());
+ }
+ });
+
+ JFrame frame = new JFrame();
+ frame.setSize(800, 600);
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ JLabel picLabel = new JLabel();
+ frame.getContentPane().add(picLabel, BorderLayout.CENTER);
+
+ frame.setVisible(true);
+
+ Disposable subscription = timeObservable.subscribe(new Consumer() {
+ @Override
+ public void accept(Date date) throws Throwable {
+ picLabel.setText(date.toString());
+ }
+ });
+
+ //subscription.dispose();
+ }
+}
diff --git a/src/ru/arhiser/rxjava/Main3.java b/src/ru/arhiser/rxjava/Main3.java
new file mode 100644
index 0000000..4688c94
--- /dev/null
+++ b/src/ru/arhiser/rxjava/Main3.java
@@ -0,0 +1,82 @@
+package ru.arhiser.rxjava;
+
+import io.reactivex.rxjava3.annotations.NonNull;
+import io.reactivex.rxjava3.core.*;
+import io.reactivex.rxjava3.disposables.Disposable;
+import io.reactivex.rxjava3.functions.Consumer;
+import io.reactivex.rxjava3.schedulers.Schedulers;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Date;
+import java.util.Timer;
+import java.util.TimerTask;
+
+public class Main3 {
+ public static void main(String[] args) {
+ JFrame frame = new JFrame();
+ frame.setSize(800, 600);
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ JTextArea label = new JTextArea();
+ JScrollPane scrollPane = new JScrollPane(label);
+
+ frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
+
+ JButton button = new JButton("Загрузить");
+
+ button.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ Single.create(new SingleOnSubscribe() {
+ @Override
+ public void subscribe(@NonNull SingleEmitter emitter) throws Throwable {
+ emitter.onSuccess(getUrlContents("https://ru.wikipedia.org/wiki/%D0%9C%D0%BE%D0%BD%D0%BE%D0%B8%D0%B4"));
+ }
+ }).subscribeOn(Schedulers.io())
+ .subscribe(new Consumer() {
+ @Override
+ public void accept(String pageText) throws Throwable {
+ label.setText(pageText);
+ }
+ }, new Consumer() {
+ @Override
+ public void accept(Throwable throwable) throws Throwable {
+
+ }
+ });
+ }
+ });
+
+ frame.getContentPane().add(button, BorderLayout.SOUTH);
+
+ frame.setVisible(true);
+ }
+
+ private static String getUrlContents(String theUrl) {
+ StringBuilder content = new StringBuilder();
+ // Use try and catch to avoid the exceptions
+ try {
+ URL url = new URL(theUrl); // creating a url object
+ URLConnection urlConnection = url.openConnection(); // creating a urlconnection object
+
+ // wrapping the urlconnection in a bufferedreader
+ BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
+ String line;
+ // reading from the urlconnection using the bufferedreader
+ while ((line = bufferedReader.readLine()) != null) {
+ content.append(line + "\n");
+ }
+ bufferedReader.close();
+ }
+ catch(Exception e) {
+ e.printStackTrace();
+ }
+ return content.toString();
+ }
+}
diff --git a/src/ru/arhiser/sort/MergeSort.java b/src/ru/arhiser/sort/MergeSort.java
index acc38fa..a46f6b8 100644
--- a/src/ru/arhiser/sort/MergeSort.java
+++ b/src/ru/arhiser/sort/MergeSort.java
@@ -3,10 +3,10 @@
public class MergeSort {
public static void main(String[] params) {
- int[] array = new int[] {64, 42, 73, 41, 32, 53, 16, 24, 57, 42, 74, 55, 36};
+ int[] array = new int[] {15,78,89,9,12,12546,8,879,16,54,1};
System.out.println(arrayToString(array));
array = mergeSort(array);
- //System.out.println(arrayToString(array));
+ System.out.println(arrayToString(array));
}
public static int[] mergeSort(int[] array) {
@@ -39,6 +39,13 @@ private static void merge(int[] src1, int src1Start, int[] src2, int src2Start,
int src1End = Math.min(src1Start + size, src1.length);
int src2End = Math.min(src2Start + size, src2.length);
+ if (src1Start + size > src1.length) {
+ for (int i = src1Start; i < src1End; i++) {
+ dest[i] = src1[i];
+ }
+ return;
+ }
+
int iterationCount = src1End - src1Start + src2End - src2Start;
for (int i = destStart; i < destStart + iterationCount; i++) {
diff --git a/src/ru/arhiser/sort/bogo/Main.java b/src/ru/arhiser/sort/bogo/Main.java
new file mode 100644
index 0000000..aeddcdf
--- /dev/null
+++ b/src/ru/arhiser/sort/bogo/Main.java
@@ -0,0 +1,41 @@
+package ru.arhiser.sort.bogo;
+
+import ru.arhiser.Utils;
+
+import java.util.Arrays;
+
+public class Main {
+ public static void main(String[] args) {
+ int[] array = new int[] {64, 42, 73, 41, 32, 53, 16, 24, 57, 42, 74, 55, 36};
+
+ Utils.measureTime(() -> {
+ while (!isSorted(array)) {
+ shuffle(array);
+ }
+ }, "bogosort");
+
+ System.out.println(Arrays.toString(array));
+
+ }
+
+ static boolean isSorted(int[] arr) {
+ for (int i = 1; i < arr.length; i++) {
+ if (arr[i - 1] > arr[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ static void shuffle(int[] arr) {
+ int temp;
+ int index;
+ for (int i = 0; i < arr.length; i++) {
+ index = (int)(Math.random() * arr.length);
+
+ temp = arr[i];
+ arr[i] = arr[index];
+ arr[index] = temp;
+ }
+ }
+}
diff --git a/src/ru/arhiser/sort/comb/BubbleSort.java b/src/ru/arhiser/sort/comb/BubbleSort.java
new file mode 100644
index 0000000..484f6a2
--- /dev/null
+++ b/src/ru/arhiser/sort/comb/BubbleSort.java
@@ -0,0 +1,19 @@
+package ru.arhiser.sort.comb;
+
+public class BubbleSort {
+
+ public static void sort(int[] array) {
+ boolean isSorted = false;
+ while (!isSorted) {
+ isSorted = true;
+ for (int i = 1; i < array.length; i++) {
+ if (array[i - 1] > array[i]) {
+ int tmp = array[i];
+ array[i] = array[i - 1];
+ array[i - 1] = tmp;
+ isSorted = false;
+ }
+ }
+ }
+ }
+}
diff --git a/src/ru/arhiser/sort/comb/BubbleSortKnuth.java b/src/ru/arhiser/sort/comb/BubbleSortKnuth.java
new file mode 100644
index 0000000..50653c8
--- /dev/null
+++ b/src/ru/arhiser/sort/comb/BubbleSortKnuth.java
@@ -0,0 +1,24 @@
+package ru.arhiser.sort.comb;
+
+public class BubbleSortKnuth {
+
+ public static int sort(int[] array) {
+ int count = 0;
+ int k = 1;
+ int j = array.length;
+ while (k > 0) {
+ k = 0;
+ for (int i = 1; i < j; i++) {
+ if (array[i - 1] > array[i]) {
+ int tmp = array[i];
+ array[i] = array[i - 1];
+ array[i - 1] = tmp;
+ k = i;
+ }
+ count++;
+ }
+ j = k;
+ }
+ return count;
+ }
+}
diff --git a/src/ru/arhiser/sort/comb/CombSort.java b/src/ru/arhiser/sort/comb/CombSort.java
new file mode 100644
index 0000000..43e265b
--- /dev/null
+++ b/src/ru/arhiser/sort/comb/CombSort.java
@@ -0,0 +1,36 @@
+package ru.arhiser.sort.comb;
+
+import java.util.Arrays;
+
+public class CombSort {
+
+ public static void main(String[] args) {
+ int[] array = new int[] {64, 73, 41, 32, 53, 16, 24, 57, 42, 74, 55, 36};
+ sort(array);
+ System.out.println(Arrays.toString(array));
+ }
+
+ public static void sort(int[] array) {
+ int gap = array.length;
+
+ boolean isSorted = false;
+ while (!isSorted || gap != 1) {
+
+ if (gap > 1) {
+ gap = gap * 10 / 13; // gap / 1.3
+ } else {
+ gap = 1;
+ }
+
+ isSorted = true;
+ for (int i = gap; i < array.length; i++) {
+ if (array[i - gap] > array[i]) {
+ int tmp = array[i];
+ array[i] = array[i - gap];
+ array[i - gap] = tmp;
+ isSorted = false;
+ }
+ }
+ }
+ }
+}
diff --git a/src/ru/arhiser/sort/comb/PerformanceTest.java b/src/ru/arhiser/sort/comb/PerformanceTest.java
new file mode 100644
index 0000000..051c178
--- /dev/null
+++ b/src/ru/arhiser/sort/comb/PerformanceTest.java
@@ -0,0 +1,54 @@
+package ru.arhiser.sort.comb;
+
+import ru.arhiser.Utils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+
+public class PerformanceTest {
+ public static void main(String[] args) {
+ ArrayList generated = new ArrayList<>();
+ for (int i = 0; i < 10000; i++) {
+ generated.add(i);
+ }
+ Collections.shuffle(generated);
+
+ int[] array1 = generated.stream().mapToInt(i->i).toArray();
+ int[] array2 = new int[array1.length];
+ System.arraycopy(array1, 0, array2, 0, array1.length);
+ int[] array3 = new int[array1.length];
+ System.arraycopy(array1, 0, array3, 0, array1.length);
+ int[] array4 = new int[array1.length];
+ System.arraycopy(array1, 0, array4, 0, array1.length);
+ int[] array5 = new int[array1.length];
+ System.arraycopy(array1, 0, array5, 0, array1.length);
+ int[] array6 = new int[array1.length];
+ System.arraycopy(array1, 0, array6, 0, array1.length);
+ int[] array7 = new int[array1.length];
+ System.arraycopy(array1, 0, array7, 0, array1.length);
+ int[] array8 = new int[array1.length];
+ System.arraycopy(array1, 0, array8, 0, array1.length);
+
+
+ Utils.measureTime(() -> BubbleSort.sort(array1), "Bubble sort");
+ Utils.measureTime(() -> BubbleSortKnuth.sort(array2), "Bubble sort Knuth");
+
+ Utils.assertTrue(Arrays.equals(array1, array2));
+
+ System.out.println();
+
+ Utils.measureTime(() -> BubbleSort.sort(array4), "Bubble sort");
+ Utils.measureTime(() -> BubbleSortKnuth.sort(array3), "Bubble sort Knuth");
+
+ System.out.println();
+
+ Utils.measureTime(() -> BubbleSort.sort(array5), "Bubble sort");
+ Utils.measureTime(() -> BubbleSortKnuth.sort(array6), "Bubble sort Knuth");
+ Utils.measureTime(() -> SelectionSort.sort(array7), "Selection sort");
+ Utils.measureTime(() -> CombSort.sort(array8), "Comb sort");
+
+ Utils.assertTrue(Arrays.equals(array6, array7));
+ Utils.assertTrue(Arrays.equals(array7, array8));
+ }
+}
diff --git a/src/ru/arhiser/sort/comb/SelectionSort.java b/src/ru/arhiser/sort/comb/SelectionSort.java
new file mode 100644
index 0000000..09359c2
--- /dev/null
+++ b/src/ru/arhiser/sort/comb/SelectionSort.java
@@ -0,0 +1,25 @@
+package ru.arhiser.sort.comb;
+
+public class SelectionSort {
+
+ public static void sort(int[] array) {
+ for (int i = 0; i < array.length; i++) {
+ int minIndex = min(array, i, array.length);
+ int tmp = array[i];
+ array[i] = array[minIndex];
+ array[minIndex] = tmp;
+ }
+ }
+
+ private static int min(int[] array, int start, int end) {
+ int minIndex = start;
+ int minValue = array[start];
+ for (int i = start + 1; i < end; i++) {
+ if (array[i] < minValue) {
+ minValue = array[i];
+ minIndex = i;
+ }
+ }
+ return minIndex;
+ }
+}
diff --git a/src/ru/arhiser/sort/comparator/Main.java b/src/ru/arhiser/sort/comparator/Main.java
new file mode 100644
index 0000000..2c9351c
--- /dev/null
+++ b/src/ru/arhiser/sort/comparator/Main.java
@@ -0,0 +1,80 @@
+package ru.arhiser.sort.comparator;
+
+import ru.arhiser.sort.count.CountSortObjects;
+
+import java.util.*;
+
+public class Main {
+ public static void main(String[] args) {
+ example2();
+ }
+
+ private static void example1() {
+ Integer[] array = new Integer[] {64, 42, 73, 41, 32, 53, 16, 24, 57, 42, 74, 55, 36};
+ Arrays.sort(array, new Comparator() {
+ @Override
+ public int compare(Integer o1, Integer o2) {
+ return o1 - o2;
+ }
+ });
+ System.out.println(Arrays.toString(array));
+ }
+
+ private static void example2() {
+ ArrayList workerList = new ArrayList<>();
+
+ workerList.add(new CountSortObjects.Worker(123, "Васильев Евстахий Борисович", "+129381832", 5));
+ workerList.add(new CountSortObjects.Worker(151, "Коновалов Степан Петрович", "+234432334", 7));
+ workerList.add(new CountSortObjects.Worker(332, "Калинин Артём Валериевич", "+2234234423", 2));
+ workerList.add(new CountSortObjects.Worker(432, "Предыбайло Григорий Анатолиевич", "+2342344234", 5));
+ workerList.add(new CountSortObjects.Worker(556, "Степанов Мирослав Андреевич", "+6678877777", 3));
+ workerList.add(new CountSortObjects.Worker(556, "Пупкин Василий Степанович", "+6678877777", 2));
+
+ bubbleSortKnuth(workerList, new Comparator() {
+ @Override
+ public int compare(CountSortObjects.Worker o1, CountSortObjects.Worker o2) {
+ int result = o1.qualification - o2.qualification;
+ if (result == 0) {
+ return o1.name.compareTo(o2.name);
+ }
+ return result;
+ }
+ });
+ /*
+ Collections.sort(workerList, new Comparator() {
+ @Override
+ public int compare(CountSortObjects.Worker o1, CountSortObjects.Worker o2) {
+ int result = o1.qualification - o2.qualification;
+ if (result == 0) {
+ return o1.name.compareTo(o2.name);
+ }
+ return result;
+ }
+ });
+ */
+
+ for(CountSortObjects.Worker worker: workerList) {
+ System.out.println(worker);
+ }
+ }
+
+ public static int bubbleSortKnuth(List list, Comparator comparator) {
+ int count = 0;
+ int k = 1;
+ int j = list.size();
+ while (k > 0) {
+ k = 0;
+ for (int i = 1; i < j; i++) {
+ if (comparator.compare(list.get(i - 1), list.get(i)) > 0) {
+ T tmp = list.get(i);
+ list.set(i, list.get(i - 1));
+ list.set(i - 1, tmp);
+ k = i;
+ }
+ count++;
+ }
+ j = k;
+ }
+ return count;
+ }
+}
diff --git a/src/ru/arhiser/sort/count/CountSort.java b/src/ru/arhiser/sort/count/CountSort.java
new file mode 100644
index 0000000..97f9980
--- /dev/null
+++ b/src/ru/arhiser/sort/count/CountSort.java
@@ -0,0 +1,59 @@
+package ru.arhiser.sort.count;
+
+import java.util.Arrays;
+
+import static ru.arhiser.sort.QuickSort.quickSort;
+
+public class CountSort {
+ public static void main(String[] params) {
+ int[] array = new int[] {64, 42, 73, 41, 32, 53, 16, 24, 57, 42, 74, 55, 36};
+ countSort(array);
+ System.out.println(Arrays.toString(array));
+ }
+
+ public static void countSort(int[] array) {
+ final int MAX_VALUE = 100;
+
+ int[] count = new int[MAX_VALUE];
+
+ for (int i = 0; i < array.length; i++) {
+ count[array[i]] = count[array[i]] + 1;
+ }
+
+ int arrayindex = 0;
+ for (int i = 0; i < count.length; i++) {
+ for (int j = 0; j < count[i]; j++) {
+ array[arrayindex] = i;
+ arrayindex++;
+ }
+ }
+ }
+
+//performance test
+
+ private static void measureTime(Runnable task) {
+ long startTime = System.currentTimeMillis();
+ task.run();
+ long elapsed = System.currentTimeMillis() - startTime;
+ System.out.println("Затраченное время: " + elapsed + " ms");
+ }
+
+ private static void test() {
+ int testLen = 100000000;
+
+ int[] arr1 = new int[testLen];
+ int[] arr2 = new int[testLen];
+
+ System.out.println("---Сравнение быстрой сортировки и сортировки подсчетом---");
+
+ for (int i = 0; i < testLen; i++) {
+ arr2[i] = arr1[i] = (int)Math.round(Math.random() * 99);
+ }
+
+ System.out.println("Быстрая сортировка:");
+ measureTime(() -> quickSort(arr1, 0, testLen - 1));
+
+ System.out.println("Сортировка подсчетом:");
+ measureTime(() -> countSort(arr2));
+ }
+}
diff --git a/src/ru/arhiser/sort/count/CountSortObjects.java b/src/ru/arhiser/sort/count/CountSortObjects.java
new file mode 100644
index 0000000..f8d0ca5
--- /dev/null
+++ b/src/ru/arhiser/sort/count/CountSortObjects.java
@@ -0,0 +1,71 @@
+package ru.arhiser.sort.count;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CountSortObjects {
+ public static void main(String[] params) {
+
+ ArrayList workerList = new ArrayList<>();
+
+ workerList.add(new Worker(123, "Васильев Евстахий Борисович", "+129381832", 5));
+ workerList.add(new Worker(151, "Коновалов Степан Петрович", "+234432334", 7));
+ workerList.add(new Worker(332, "Калинин Артём Валериевич", "+2234234423", 2));
+ workerList.add(new Worker(432, "Предыбайло Григорий Анатолиевич", "+2342344234", 5));
+ workerList.add(new Worker(556, "Степанов Мирослав Андреевич", "+6678877777", 3));
+ workerList.add(new Worker(556, "Пупкин Василий Степанович", "+6678877777", 2));
+
+ for(Worker worker: countSortObject(workerList)) {
+ System.out.println(worker);
+ }
+ }
+
+ public static Worker[] countSortObject(List workers) {
+
+ final int MAX_VALUE = 10;
+
+ int[] count = new int[MAX_VALUE];
+
+ for (int i = 0; i < workers.size(); i++) {
+ count[workers.get(i).qualification] = count[workers.get(i).qualification] + 1;
+ }
+
+ Worker[] out = new Worker[workers.size()];
+
+ for (int i = 1; i < count.length; i++) {
+ count[i] = count[i] + count[i - 1];
+ }
+
+ for (int i = workers.size() - 1; i >= 0 ; i--) {
+ Worker worker = workers.get(i);
+ out[count[worker.qualification] - 1] = worker;
+ count[worker.qualification]--;
+ }
+
+ return out;
+ }
+
+ static class Worker {
+ int id;
+ String name;
+ String phone;
+ int qualification;
+
+ public Worker(int id, String name, String phone, int qualification) {
+ this.id = id;
+ this.name = name;
+ this.phone = phone;
+ this.qualification = qualification;
+ }
+
+ @Override
+ public String toString() {
+ return "Worker{" +
+ "id=" + id +
+ ", name='" + name + '\'' +
+ ", phone='" + phone + '\'' +
+ ", qualification=" + qualification +
+ '}';
+ }
+ }
+}
diff --git a/src/ru/arhiser/sort/insertion/InsertionSort.java b/src/ru/arhiser/sort/insertion/InsertionSort.java
new file mode 100644
index 0000000..480b349
--- /dev/null
+++ b/src/ru/arhiser/sort/insertion/InsertionSort.java
@@ -0,0 +1,24 @@
+package ru.arhiser.sort.insertion;
+
+import java.util.Arrays;
+
+public class InsertionSort {
+
+ public static void main(String[] params) {
+ int[] array = new int[] {64, 42, 73, 41, 32, 53, 16, 24, 57, 42, 74, 55, 36};
+ insertionSort(array);
+ System.out.println(Arrays.toString(array));
+ }
+
+ public static void insertionSort(int[] array) {
+ for (int i = 1; i < array.length; i++) {
+ int current = array[i];
+ int j = i;
+ while (j > 0 && array[j - 1] > current) {
+ array[j] = array[j - 1];
+ j--;
+ }
+ array[j] = current;
+ }
+ }
+}
diff --git a/src/ru/arhiser/visual/engine/animator/Animator.java b/src/ru/arhiser/visual/engine/animator/Animator.java
new file mode 100644
index 0000000..d687cd2
--- /dev/null
+++ b/src/ru/arhiser/visual/engine/animator/Animator.java
@@ -0,0 +1,5 @@
+package ru.arhiser.visual.engine.animator;
+
+public interface Animator {
+ public boolean makeStep();
+}
diff --git a/src/ru/arhiser/visual/engine/animator/AnimatorGroup.java b/src/ru/arhiser/visual/engine/animator/AnimatorGroup.java
new file mode 100644
index 0000000..cc75b7e
--- /dev/null
+++ b/src/ru/arhiser/visual/engine/animator/AnimatorGroup.java
@@ -0,0 +1,27 @@
+package ru.arhiser.visual.engine.animator;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class AnimatorGroup implements Animator {
+ ArrayList animators = new ArrayList<>();
+
+ public AnimatorGroup(Animator... animators) {
+ this.animators.addAll(Arrays.asList(animators));
+ }
+
+ public AnimatorGroup(List animators) {
+ this.animators.addAll(animators);
+ }
+
+
+ @Override
+ public boolean makeStep() {
+ boolean notEnded = false;
+ for (Animator animator: animators) {
+ notEnded |= animator.makeStep();
+ }
+ return notEnded;
+ }
+}
diff --git a/src/ru/arhiser/visual/engine/animator/AnimatorSequence.java b/src/ru/arhiser/visual/engine/animator/AnimatorSequence.java
new file mode 100644
index 0000000..5fa6dcd
--- /dev/null
+++ b/src/ru/arhiser/visual/engine/animator/AnimatorSequence.java
@@ -0,0 +1,29 @@
+package ru.arhiser.visual.engine.animator;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class AnimatorSequence implements Animator {
+ ArrayList animators = new ArrayList<>();
+
+ public AnimatorSequence(Animator... animators) {
+ this.animators.addAll(Arrays.asList(animators));
+ }
+
+ public AnimatorSequence(List animators) {
+ this.animators.addAll(animators);
+ }
+
+
+ @Override
+ public boolean makeStep() {
+ if (!animators.isEmpty()) {
+ boolean ended = !animators.get(0).makeStep();
+ if (ended) {
+ animators.remove(0);
+ }
+ }
+ return !animators.isEmpty();
+ }
+}
diff --git a/src/ru/arhiser/visual/engine/animator/PropertyAnimator.java b/src/ru/arhiser/visual/engine/animator/PropertyAnimator.java
new file mode 100644
index 0000000..bb814d7
--- /dev/null
+++ b/src/ru/arhiser/visual/engine/animator/PropertyAnimator.java
@@ -0,0 +1,36 @@
+package ru.arhiser.visual.engine.animator;
+
+import java.util.function.Consumer;
+
+public class PropertyAnimator implements Animator {
+ protected int steps;
+ protected int currentStep = 1;
+
+ protected T startValue;
+ protected T endValue;
+
+ protected Evaluator evaluator;
+
+ protected Consumer setter;
+
+ public interface Evaluator {
+ T evaluate(T startValue, T endValue, int steps, int currentStep);
+ }
+
+ public PropertyAnimator(T startValue, T endValue, int steps, Consumer setter, Evaluator evaluator) {
+ this.steps = steps;
+ this.startValue = startValue;
+ this.endValue = endValue;
+ this.setter = setter;
+ this.evaluator = evaluator;
+ }
+
+ @Override
+ public boolean makeStep() {
+ if (currentStep <= steps) {
+ setter.accept(evaluator.evaluate(startValue, endValue, steps, currentStep));
+ currentStep += 1;
+ }
+ return currentStep <= steps;
+ }
+}
diff --git a/src/ru/arhiser/visual/engine/animator/evaluator/IntLinearEvaluator.java b/src/ru/arhiser/visual/engine/animator/evaluator/IntLinearEvaluator.java
new file mode 100644
index 0000000..8cd68f0
--- /dev/null
+++ b/src/ru/arhiser/visual/engine/animator/evaluator/IntLinearEvaluator.java
@@ -0,0 +1,12 @@
+package ru.arhiser.visual.engine.animator.evaluator;
+
+import ru.arhiser.visual.engine.animator.PropertyAnimator;
+
+public class IntLinearEvaluator implements PropertyAnimator.Evaluator {
+
+ @Override
+ public Integer evaluate(Integer startValue, Integer endValue, int steps, int currentStep) {
+ int dif = endValue - startValue;
+ return startValue + Math.round(((float) currentStep / steps) * dif);
+ }
+}
diff --git a/src/ru/arhiser/visual/engine/animator/evaluator/RGBLinearEvaluator.java b/src/ru/arhiser/visual/engine/animator/evaluator/RGBLinearEvaluator.java
new file mode 100644
index 0000000..6c0ccca
--- /dev/null
+++ b/src/ru/arhiser/visual/engine/animator/evaluator/RGBLinearEvaluator.java
@@ -0,0 +1,23 @@
+package ru.arhiser.visual.engine.animator.evaluator;
+
+import ru.arhiser.visual.engine.animator.PropertyAnimator;
+
+public class RGBLinearEvaluator implements PropertyAnimator.Evaluator {
+
+ @Override
+ public Integer evaluate(Integer startValue, Integer endValue, int steps, int currentStep) {
+ int rStart = startValue >> 16 & 0xff;
+ int gStart = startValue >> 8 & 0xff;
+ int bStart = startValue & 0xff;
+
+ int rEnd = endValue >> 16 & 0xff;
+ int gEnd = endValue >> 8 & 0xff;
+ int bEnd = endValue & 0xff;
+
+ int rValue = rStart + Math.round(((float) currentStep / steps) * (rEnd - rStart));
+ int gValue = gStart + Math.round(((float) currentStep / steps) * (gEnd - gStart));
+ int bValue = bStart + Math.round(((float) currentStep / steps) * (bEnd - bStart));
+
+ return 0xff000000 | rValue << 16 | gValue << 8 | bValue;
+ }
+}
diff --git a/src/ru/arhiser/visual/engine/drawable/DrawableGroup.java b/src/ru/arhiser/visual/engine/drawable/DrawableGroup.java
new file mode 100644
index 0000000..52a506f
--- /dev/null
+++ b/src/ru/arhiser/visual/engine/drawable/DrawableGroup.java
@@ -0,0 +1,21 @@
+package ru.arhiser.visual.engine.drawable;
+
+import ru.arhiser.visual.raster.Raster;
+
+import java.util.ArrayList;
+
+public class DrawableGroup extends DrawableObject {
+ protected ArrayList drawables = new ArrayList<>();
+
+ public DrawableGroup(int x, int y, int width, int height) {
+ super(x, y, width, height);
+ }
+
+
+ @Override
+ public void draw(Raster raster) {
+ for(DrawableObject drawable: drawables) {
+ drawable.draw(raster);
+ }
+ }
+}
diff --git a/src/ru/arhiser/visual/engine/drawable/DrawableObject.java b/src/ru/arhiser/visual/engine/drawable/DrawableObject.java
new file mode 100644
index 0000000..bd263e2
--- /dev/null
+++ b/src/ru/arhiser/visual/engine/drawable/DrawableObject.java
@@ -0,0 +1,60 @@
+package ru.arhiser.visual.engine.drawable;
+
+import ru.arhiser.visual.raster.Raster;
+
+public abstract class DrawableObject {
+ protected int x;
+ protected int y;
+ protected int width;
+ protected int height;
+ protected int color;
+
+ public DrawableObject(int x, int y, int width, int height) {
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ }
+
+ public abstract void draw(Raster raster);
+
+ public int getX() {
+ return x;
+ }
+
+ public void setX(int x) {
+ this.x = x;
+ }
+
+ public int getY() {
+ return y;
+ }
+
+ public void setY(int y) {
+ this.y = y;
+ }
+
+ public int getWidth() {
+ return width;
+ }
+
+ public void setWidth(int width) {
+ this.width = width;
+ }
+
+ public int getHeight() {
+ return height;
+ }
+
+ public void setHeight(int height) {
+ this.height = height;
+ }
+
+ public int getColor() {
+ return color;
+ }
+
+ public void setColor(int color) {
+ this.color = color;
+ }
+}
diff --git a/src/ru/arhiser/visual/engine/drawable/Rectangle.java b/src/ru/arhiser/visual/engine/drawable/Rectangle.java
new file mode 100644
index 0000000..53ebf1a
--- /dev/null
+++ b/src/ru/arhiser/visual/engine/drawable/Rectangle.java
@@ -0,0 +1,20 @@
+package ru.arhiser.visual.engine.drawable;
+
+import ru.arhiser.visual.raster.Raster;
+
+public class Rectangle extends DrawableObject {
+
+ public Rectangle(int x, int y, int width, int height, int color) {
+ super(x, y, width, height);
+ this.color = color;
+ }
+
+ @Override
+ public void draw(Raster raster) {
+ for (int i = y; i < y + height; i++) {
+ for (int j = x; j < x + width; j++) {
+ raster.getPixels()[i * raster.getWidth() + j] = color;
+ }
+ }
+ }
+}
diff --git a/src/ru/arhiser/visual/engine/scene/AnimationProducer.java b/src/ru/arhiser/visual/engine/scene/AnimationProducer.java
new file mode 100644
index 0000000..7a4398d
--- /dev/null
+++ b/src/ru/arhiser/visual/engine/scene/AnimationProducer.java
@@ -0,0 +1,10 @@
+package ru.arhiser.visual.engine.scene;
+
+import ru.arhiser.visual.engine.animator.Animator;
+import ru.arhiser.visual.engine.drawable.DrawableObject;
+
+import java.util.List;
+
+public interface AnimationProducer {
+ List makeAnimation(T sceneRoot);
+}
diff --git a/src/ru/arhiser/visual/engine/scene/Scene.java b/src/ru/arhiser/visual/engine/scene/Scene.java
new file mode 100644
index 0000000..0f819b1
--- /dev/null
+++ b/src/ru/arhiser/visual/engine/scene/Scene.java
@@ -0,0 +1,47 @@
+package ru.arhiser.visual.engine.scene;
+
+import ru.arhiser.visual.engine.animator.Animator;
+import ru.arhiser.visual.raster.Raster;
+import ru.arhiser.visual.engine.drawable.DrawableObject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Scene {
+ Raster raster;
+
+ DrawableObject root;
+
+ ArrayList animatorQueue = new ArrayList<>();
+
+ int getWidth() {
+ return raster.getWidth();
+ }
+
+ int getHeight() {
+ return raster.getHeight();
+ }
+
+ public Scene(Raster raster, DrawableObject root, List animators) {
+ this.raster = raster;
+ this.root = root;
+ animatorQueue.addAll(animators);
+ }
+
+ public boolean renderNext() {
+ root.draw(raster);
+ return makeAnimationStep();
+ }
+
+ public boolean makeAnimationStep() {
+ if (animatorQueue.isEmpty()) {
+ return false;
+ }
+ Animator animator = animatorQueue.get(0);
+ boolean result = animator.makeStep();
+ if (!result) {
+ animatorQueue.remove(0);
+ }
+ return true;
+ }
+}
diff --git a/src/ru/arhiser/visual/impl/IntArrayDrawable.java b/src/ru/arhiser/visual/impl/IntArrayDrawable.java
new file mode 100644
index 0000000..ff7c1f2
--- /dev/null
+++ b/src/ru/arhiser/visual/impl/IntArrayDrawable.java
@@ -0,0 +1,62 @@
+package ru.arhiser.visual.impl;
+
+import ru.arhiser.visual.engine.drawable.DrawableGroup;
+import ru.arhiser.visual.engine.drawable.DrawableObject;
+import ru.arhiser.visual.engine.drawable.Rectangle;
+import ru.arhiser.visual.raster.Raster;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+
+public class IntArrayDrawable extends DrawableGroup {
+
+ HashMap drawableMap = new HashMap<>();
+
+ int padding = 10;
+
+ int cellWidth;
+
+ int arrayMaxValue;
+
+ public IntArrayDrawable(int x, int y, int width, int height, int[] array) {
+ super(x, y, width, height);
+
+ arrayMaxValue = Arrays.stream(array).max().getAsInt();
+
+ cellWidth = (width - (array.length + 1) * padding) / array.length;
+
+ for (int i = 0; i < array.length; i++) {
+ int position = getPositionX(i);
+ DrawableObject drawableObject = new Rectangle(position, height - getCellHeight(array[i]), cellWidth, getCellHeight(array[i]), 0xffffffff - array[i] * 2);
+ drawableMap.put(array[i], drawableObject);
+ drawables.add(drawableObject);
+ }
+ }
+
+ public DrawableObject getDrawableForIndex(int index) {
+ return drawableMap.get(index);
+ }
+
+ public int getPositionX(int index) {
+ return (index + 1) * padding + index * cellWidth;
+ }
+
+ private int getCellHeight(int value) {
+ return (int)(getHeight() * ((float)value / arrayMaxValue));
+ }
+
+ @Override
+ public void draw(Raster raster) {
+ for (int i = y; i < y + height; i++) {
+ for (int j = x; j < x + width; j++) {
+ raster.getPixels()[i * raster.getWidth() + j] = 0xff000000;
+ }
+ }
+ super.draw(raster);
+ }
+
+ public List getDrawables() {
+ return drawables;
+ }
+}
diff --git a/src/ru/arhiser/visual/raster/Raster.java b/src/ru/arhiser/visual/raster/Raster.java
new file mode 100644
index 0000000..8a01c4e
--- /dev/null
+++ b/src/ru/arhiser/visual/raster/Raster.java
@@ -0,0 +1,29 @@
+package ru.arhiser.visual.raster;
+
+public class Raster {
+ int width;
+ int height;
+ int[] pixels;
+
+ public Raster(int width, int height) {
+ this.width = width;
+ this.height = height;
+ this.pixels = new int[width * height];
+ }
+
+ public int getWidth() {
+ return width;
+ }
+
+ public int getHeight() {
+ return height;
+ }
+
+ public int[] getPixels() {
+ return pixels;
+ }
+
+ public int getSize() {
+ return pixels.length;
+ }
+}
diff --git a/src/ru/arhiser/visual/raster/RasterWindow.java b/src/ru/arhiser/visual/raster/RasterWindow.java
new file mode 100644
index 0000000..06f6665
--- /dev/null
+++ b/src/ru/arhiser/visual/raster/RasterWindow.java
@@ -0,0 +1,54 @@
+package ru.arhiser.visual.raster;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferInt;
+
+public class RasterWindow extends JFrame {
+
+ BufferedImage image;
+ Raster raster;
+
+ public static void main(String[] arg) {
+ int width = 800;
+ int height = 600;
+
+ Raster raster = new Raster(width, height);
+
+ for (int i = 0; i < raster.getSize(); i++) {
+ raster.pixels[i] = 0xff000000 | i;
+ }
+
+ RasterWindow rasterWindow = new RasterWindow(raster);
+ }
+
+ public RasterWindow(Raster raster) {
+ super("Raster");
+ this.raster = raster;
+
+ image = new BufferedImage(raster.getWidth(), raster.getHeight(), BufferedImage.TYPE_INT_ARGB);
+
+ setSize(raster.getWidth(), raster.getHeight());
+
+ setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+
+ JLabel picLabel = new JLabel(new ImageIcon(image));
+
+ BorderLayout borderLayout = new BorderLayout();
+ getContentPane().setLayout(borderLayout);
+ getContentPane().add(picLabel, BorderLayout.CENTER);
+
+ setVisible(true);
+
+ updateRaster();
+ }
+
+ public void updateRaster() {
+ int[] pixels = ((DataBufferInt)image.getRaster().getDataBuffer()).getData();
+ for (int i = 0; i < raster.width * raster.height; i++) {
+ pixels[i] = raster.pixels[i];
+ }
+ repaint();
+ }
+}
diff --git a/src/ru/arhiser/visual/samples/array/ArraySample.java b/src/ru/arhiser/visual/samples/array/ArraySample.java
new file mode 100644
index 0000000..2dacd22
--- /dev/null
+++ b/src/ru/arhiser/visual/samples/array/ArraySample.java
@@ -0,0 +1,48 @@
+package ru.arhiser.visual.samples.array;
+
+import ru.arhiser.sort.QuickSort;
+import ru.arhiser.visual.engine.animator.Animator;
+import ru.arhiser.visual.engine.scene.Scene;
+import ru.arhiser.visual.impl.IntArrayDrawable;
+import ru.arhiser.visual.raster.Raster;
+import ru.arhiser.visual.raster.RasterWindow;
+
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+
+public class ArraySample {
+ public static void main(String[] args) {
+
+ Raster raster = new Raster(800, 600);
+
+ RasterWindow rasterWindow = new RasterWindow(raster);
+
+ int[] array = new int[] {64, 42, 68, 41, 32, 53, 16, 24, 57, 48, 74, 55, 36};
+
+ IntArrayDrawable arrayDrawable = new IntArrayDrawable(0, 0, 800, 600, array);
+
+ CombSortAnimationProducer combSortAnimationProducer = new CombSortAnimationProducer(array);
+ List animatorList = combSortAnimationProducer.makeAnimation(arrayDrawable);
+
+ Scene scene = new Scene(raster, arrayDrawable, animatorList);
+
+ RasterFileWriter rasterFileWriter = new RasterFileWriter(raster, "D:\\arhiser\\youtube\\comb_sort\\comb\\");
+
+ Timer timer = new Timer();
+ timer.scheduleAtFixedRate(new TimerTask() {
+ @Override
+ public void run() {
+ boolean finished;
+ finished = !scene.renderNext();
+ //rasterFileWriter.writeNextFrame();
+ rasterWindow.updateRaster();
+
+ if (finished) {
+ this.cancel();
+ timer.cancel();
+ }
+ }
+ }, 0, 1);
+ }
+}
diff --git a/src/ru/arhiser/visual/samples/array/BubbleSortAnimationProducer.java b/src/ru/arhiser/visual/samples/array/BubbleSortAnimationProducer.java
new file mode 100644
index 0000000..bbf301b
--- /dev/null
+++ b/src/ru/arhiser/visual/samples/array/BubbleSortAnimationProducer.java
@@ -0,0 +1,77 @@
+package ru.arhiser.visual.samples.array;
+
+import ru.arhiser.visual.engine.animator.Animator;
+import ru.arhiser.visual.engine.scene.AnimationProducer;
+import ru.arhiser.visual.impl.IntArrayDrawable;
+
+import java.util.List;
+
+public class BubbleSortAnimationProducer implements AnimationProducer {
+
+ int[] array;
+
+ public BubbleSortAnimationProducer(int[] array) {
+ this.array = array;
+ }
+
+ @Override
+ public List makeAnimation(IntArrayDrawable sceneRoot) {
+
+ SortAnimationRecorder sortAnimationRecorder = new SortAnimationRecorder(sceneRoot, array);
+
+ for (int i = 0; i < array.length; i++) {
+ for (int j = 1; j < array.length - i; j++) {
+ if (array[j - 1] > array[j]) {
+ int tmp = array[j - 1];
+ array[j - 1] = array[j];
+ array[j] = tmp;
+
+ sortAnimationRecorder.recordStep(array);
+ }
+ }
+ }
+
+ return sortAnimationRecorder.getAnimationQueue();
+ }
+/*
+ @Override
+ public List makeAnimation(IntArrayDrawable sceneRoot) {
+ ArrayList animators = new ArrayList<>();
+
+ ArrayList positions = new ArrayList<>();
+ for (DrawableObject drawableObject: sceneRoot.getDrawables()) {
+ positions.add(drawableObject.getX());
+ }
+
+ for (int i = 0; i < array.length; i++) {
+ for (int j = 1; j < array.length - i; j++) {
+ if (array[j - 1] > array[j]) {
+
+ DrawableObject drawable1 = sceneRoot.getDrawableForIndex(array[j - 1]);
+ DrawableObject drawable2 = sceneRoot.getDrawableForIndex(array[j]);
+ PropertyAnimator animator1 = new PropertyAnimator<>(drawable1.getX(), drawable2.getX(),
+ 30, drawable1::setX, new IntLinearEvaluator());
+ PropertyAnimator animator2 = new PropertyAnimator<>(drawable2.getX(), drawable1.getX(),
+ 30, drawable2::setX, new IntLinearEvaluator());
+ AnimatorGroup animatorGroup = new AnimatorGroup(animator1, animator2);
+ animators.add(animatorGroup);
+
+ int x = drawable1.getX();
+ drawable1.setX(drawable2.getX());
+ drawable2.setX(x);
+
+ int tmp = array[j - 1];
+ array[j - 1] = array[j];
+ array[j] = tmp;
+ }
+ }
+ }
+
+ for (int i = 0; i < positions.size(); i++) {
+ sceneRoot.getDrawables().get(i).setX(positions.get(i));
+ }
+
+ return animators;
+ }
+ */
+}
diff --git a/src/ru/arhiser/visual/samples/array/CombSortAnimationProducer.java b/src/ru/arhiser/visual/samples/array/CombSortAnimationProducer.java
new file mode 100644
index 0000000..f57181c
--- /dev/null
+++ b/src/ru/arhiser/visual/samples/array/CombSortAnimationProducer.java
@@ -0,0 +1,90 @@
+package ru.arhiser.visual.samples.array;
+
+import ru.arhiser.visual.engine.animator.Animator;
+import ru.arhiser.visual.engine.scene.AnimationProducer;
+import ru.arhiser.visual.impl.IntArrayDrawable;
+
+import java.util.List;
+
+public class CombSortAnimationProducer implements AnimationProducer {
+
+ int[] array;
+
+ public CombSortAnimationProducer(int[] array) {
+ this.array = array;
+ }
+
+ @Override
+ public List makeAnimation(IntArrayDrawable sceneRoot) {
+
+ SortAnimationRecorder sortAnimationRecorder = new SortAnimationRecorder(sceneRoot, array);
+
+ int gap = array.length;
+
+ boolean isSorted = false;
+ while (!isSorted || gap != 1) {
+
+ if (gap > 1) {
+ gap = gap * 10 / 13; // gap / 1.3
+ } else {
+ gap = 1;
+ }
+
+ isSorted = true;
+ for (int i = gap; i < array.length; i++) {
+ sortAnimationRecorder.highliteElements(array[i - gap], array[i]);
+ if (array[i - gap] > array[i]) {
+ int tmp = array[i];
+ array[i] = array[i - gap];
+ array[i - gap] = tmp;
+ isSorted = false;
+
+ sortAnimationRecorder.recordStep(array);
+ }
+ }
+ }
+
+ return sortAnimationRecorder.getAnimationQueue();
+ }
+/*
+ @Override
+ public List makeAnimation(IntArrayDrawable sceneRoot) {
+ ArrayList animators = new ArrayList<>();
+
+ ArrayList positions = new ArrayList<>();
+ for (DrawableObject drawableObject: sceneRoot.getDrawables()) {
+ positions.add(drawableObject.getX());
+ }
+
+ for (int i = 0; i < array.length; i++) {
+ for (int j = 1; j < array.length - i; j++) {
+ if (array[j - 1] > array[j]) {
+
+ DrawableObject drawable1 = sceneRoot.getDrawableForIndex(array[j - 1]);
+ DrawableObject drawable2 = sceneRoot.getDrawableForIndex(array[j]);
+ PropertyAnimator animator1 = new PropertyAnimator<>(drawable1.getX(), drawable2.getX(),
+ 30, drawable1::setX, new IntLinearEvaluator());
+ PropertyAnimator animator2 = new PropertyAnimator<>(drawable2.getX(), drawable1.getX(),
+ 30, drawable2::setX, new IntLinearEvaluator());
+ AnimatorGroup animatorGroup = new AnimatorGroup(animator1, animator2);
+ animators.add(animatorGroup);
+
+ int x = drawable1.getX();
+ drawable1.setX(drawable2.getX());
+ drawable2.setX(x);
+
+ int tmp = array[j - 1];
+ array[j - 1] = array[j];
+ array[j] = tmp;
+ }
+ }
+ }
+
+ for (int i = 0; i < positions.size(); i++) {
+ sceneRoot.getDrawables().get(i).setX(positions.get(i));
+ }
+
+ return animators;
+ }
+ */
+}
diff --git a/src/ru/arhiser/visual/samples/array/InsertionSortAnimationProducer.java b/src/ru/arhiser/visual/samples/array/InsertionSortAnimationProducer.java
new file mode 100644
index 0000000..1bd39c6
--- /dev/null
+++ b/src/ru/arhiser/visual/samples/array/InsertionSortAnimationProducer.java
@@ -0,0 +1,50 @@
+package ru.arhiser.visual.samples.array;
+
+import ru.arhiser.visual.engine.animator.Animator;
+import ru.arhiser.visual.engine.scene.AnimationProducer;
+import ru.arhiser.visual.impl.IntArrayDrawable;
+
+import java.util.List;
+
+public class InsertionSortAnimationProducer implements AnimationProducer {
+
+ int[] array;
+
+ public InsertionSortAnimationProducer(int[] array) {
+ this.array = array;
+ }
+
+ @Override
+ public List makeAnimation(IntArrayDrawable sceneRoot) {
+
+ SortAnimationRecorder sortAnimationRecorder = new SortAnimationRecorder(sceneRoot, array);
+/*
+ for (int i = 1; i < array.length; i++) {
+ int current = array[i];
+ int j = i;
+ while (j > 0 && array[j - 1] > current) {
+ array[j] = array[j - 1];
+ array[j - 1] = current;
+ j--;
+ sortAnimationRecorder.recordStep(array);
+ }
+ array[j] = current;
+ sortAnimationRecorder.recordStep(array);
+ }
+ */
+
+ for (int i = 1; i < array.length; i++) {
+ int current = array[i];
+ int j = i;
+ while (j > 0 && array[j - 1] > current) {
+ array[j] = array[j - 1];
+ j--;
+ }
+ array[j] = current;
+ sortAnimationRecorder.recordStep(array);
+ }
+
+ return sortAnimationRecorder.getAnimationQueue();
+ }
+
+}
diff --git a/src/ru/arhiser/visual/samples/array/QuickSortAnimationProducer.java b/src/ru/arhiser/visual/samples/array/QuickSortAnimationProducer.java
new file mode 100644
index 0000000..96e0129
--- /dev/null
+++ b/src/ru/arhiser/visual/samples/array/QuickSortAnimationProducer.java
@@ -0,0 +1,71 @@
+package ru.arhiser.visual.samples.array;
+
+import ru.arhiser.visual.engine.animator.Animator;
+import ru.arhiser.visual.engine.scene.AnimationProducer;
+import ru.arhiser.visual.impl.IntArrayDrawable;
+
+import java.util.List;
+
+public class QuickSortAnimationProducer implements AnimationProducer {
+
+ int[] array;
+
+ SortAnimationRecorder sortAnimationRecorder;
+
+ public QuickSortAnimationProducer(int[] array) {
+ this.array = array;
+ }
+
+ @Override
+ public List makeAnimation(IntArrayDrawable sceneRoot) {
+
+ sortAnimationRecorder = new SortAnimationRecorder(sceneRoot, array);
+
+ quickSort(array, 0, array.length - 1);
+
+ return sortAnimationRecorder.getAnimationQueue();
+ }
+
+ public void quickSort(int[] arr, int from, int to) {
+
+ if (from < to) {
+
+ int divideIndex = partition(arr, from, to);
+
+ quickSort(arr, from, divideIndex - 1);
+
+ quickSort(arr, divideIndex, to);
+ }
+ }
+
+ private int partition(int[] arr, int from, int to) {
+ int rightIndex = to;
+ int leftIndex = from;
+
+ int pivot = arr[from + (to - from) / 2];
+ while (leftIndex <= rightIndex) {
+
+ while (arr[leftIndex] < pivot) {
+ leftIndex++;
+ }
+
+ while (arr[rightIndex] > pivot) {
+ rightIndex--;
+ }
+
+ if (leftIndex <= rightIndex) {
+ swap(arr, rightIndex, leftIndex);
+ leftIndex++;
+ rightIndex--;
+ }
+ }
+ return leftIndex;
+ }
+
+ private void swap(int[] array, int index1, int index2) {
+ int tmp = array[index1];
+ array[index1] = array[index2];
+ array[index2] = tmp;
+ sortAnimationRecorder.recordStep(array);
+ }
+}
diff --git a/src/ru/arhiser/visual/samples/array/RasterFileWriter.java b/src/ru/arhiser/visual/samples/array/RasterFileWriter.java
new file mode 100644
index 0000000..c47e7e0
--- /dev/null
+++ b/src/ru/arhiser/visual/samples/array/RasterFileWriter.java
@@ -0,0 +1,41 @@
+package ru.arhiser.visual.samples.array;
+
+import ru.arhiser.visual.raster.Raster;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferInt;
+import java.io.File;
+import java.io.IOException;
+
+public class RasterFileWriter {
+
+ Raster raster;
+
+ BufferedImage image;
+
+ String path;
+
+ int frameNumber;
+
+ public RasterFileWriter(Raster raster, String path) {
+ this.raster = raster;
+ this.path = path;
+ image = new BufferedImage(raster.getWidth(), raster.getHeight(), BufferedImage.TYPE_INT_ARGB);
+ }
+
+ public void writeNextFrame() {
+ try {
+ int[] pixels = ((DataBufferInt)image.getRaster().getDataBuffer()).getData();
+ for (int i = 0; i < raster.getWidth() * raster.getHeight(); i++) {
+ pixels[i] = raster.getPixels()[i];
+ }
+
+ File file = new File(path + "img_" + frameNumber + ".png");
+ ImageIO.write(image, "png", file);
+ frameNumber += 1;
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/ru/arhiser/visual/samples/array/SelectionSortAnimationProducer.java b/src/ru/arhiser/visual/samples/array/SelectionSortAnimationProducer.java
new file mode 100644
index 0000000..f2349d4
--- /dev/null
+++ b/src/ru/arhiser/visual/samples/array/SelectionSortAnimationProducer.java
@@ -0,0 +1,44 @@
+package ru.arhiser.visual.samples.array;
+
+import ru.arhiser.visual.engine.animator.Animator;
+import ru.arhiser.visual.engine.scene.AnimationProducer;
+import ru.arhiser.visual.impl.IntArrayDrawable;
+
+import java.util.List;
+
+public class SelectionSortAnimationProducer implements AnimationProducer {
+
+ int[] array;
+
+ public SelectionSortAnimationProducer(int[] array) {
+ this.array = array;
+ }
+
+ @Override
+ public List makeAnimation(IntArrayDrawable sceneRoot) {
+
+ SortAnimationRecorder sortAnimationRecorder = new SortAnimationRecorder(sceneRoot, array);
+
+ for (int i = 0; i < array.length; i++) {
+ int minIndex = min(array, i, array.length);
+ int tmp = array[i];
+ array[i] = array[minIndex];
+ array[minIndex] = tmp;
+ sortAnimationRecorder.recordStep(array);
+ }
+
+ return sortAnimationRecorder.getAnimationQueue();
+ }
+
+ private static int min(int[] array, int start, int end) {
+ int minIndex = start;
+ int minValue = array[start];
+ for (int i = start + 1; i < end; i++) {
+ if (array[i] < minValue) {
+ minValue = array[i];
+ minIndex = i;
+ }
+ }
+ return minIndex;
+ }
+}
diff --git a/src/ru/arhiser/visual/samples/array/SortAnimationRecorder.java b/src/ru/arhiser/visual/samples/array/SortAnimationRecorder.java
new file mode 100644
index 0000000..36ea043
--- /dev/null
+++ b/src/ru/arhiser/visual/samples/array/SortAnimationRecorder.java
@@ -0,0 +1,106 @@
+package ru.arhiser.visual.samples.array;
+
+import ru.arhiser.visual.engine.animator.Animator;
+import ru.arhiser.visual.engine.animator.AnimatorGroup;
+import ru.arhiser.visual.engine.animator.AnimatorSequence;
+import ru.arhiser.visual.engine.animator.PropertyAnimator;
+import ru.arhiser.visual.engine.animator.evaluator.IntLinearEvaluator;
+import ru.arhiser.visual.engine.animator.evaluator.RGBLinearEvaluator;
+import ru.arhiser.visual.engine.drawable.DrawableObject;
+import ru.arhiser.visual.impl.IntArrayDrawable;
+
+import javax.swing.*;
+import java.util.ArrayList;
+import java.util.List;
+
+public class SortAnimationRecorder {
+
+ IntArrayDrawable root;
+
+ int[] lastArray;
+
+ ArrayList animatorQueue = new ArrayList<>();
+
+ public SortAnimationRecorder(IntArrayDrawable root, int[] array) {
+ this.lastArray = copyArray(array);
+ this.root = root;
+ }
+
+ private int[] copyArray(int[] array) {
+ int[] arrayCopy = new int[array.length];
+ System.arraycopy(array, 0, arrayCopy, 0, array.length);
+ return arrayCopy;
+ }
+
+ public void highliteElements(int ... elements) {
+ AnimatorGroup group = new AnimatorGroup();
+ List animators = new ArrayList<>();
+ for(Integer element: elements) {
+ DrawableObject drawable = root.getDrawableForIndex(element);
+ int color = drawable.getColor();
+
+ AnimatorSequence sequence = new AnimatorSequence(
+ new PropertyAnimator<>(color, 0xff0000ff, 15, drawable::setColor, new RGBLinearEvaluator()),
+ new PropertyAnimator<>(0xff4080ff, color, 15, drawable::setColor, new RGBLinearEvaluator())
+ );
+
+ animators.add(sequence);
+ }
+ animatorQueue.add(new AnimatorGroup(animators));
+ }
+
+ public void recordStep(int[] array) {
+ ArrayList moved = new ArrayList<>();
+ for (int i = 0; i < array.length; i++) {
+ if (lastArray[i] != array[i]) {
+ moved.add(lastArray[i]);
+ }
+ }
+ if (!moved.isEmpty()) {
+ ArrayList animators = new ArrayList<>();
+ for (Integer movedElement: moved) {
+ int startX = root.getPositionX(indexOf(movedElement, lastArray));
+ int endX = root.getPositionX(indexOf(movedElement, array));
+
+ DrawableObject drawable = root.getDrawableForIndex(movedElement);
+
+ int color = drawable.getColor();
+
+ Animator animator = new PropertyAnimator<>(startX, endX, 15, drawable::setX, new IntLinearEvaluator());
+/*
+ AnimatorSequence sequence = new AnimatorSequence(
+ new PropertyAnimator<>(color, 0xff0000ff, 15, drawable::setColor, new RGBLinearEvaluator()),
+ new PropertyAnimator<>(startX, endX, 15, drawable::setX, new IntLinearEvaluator()),
+ new PropertyAnimator<>(0xff4080ff, color, 15, drawable::setColor, new RGBLinearEvaluator())
+ );
+*/
+ animators.add(animator);
+ }
+ animatorQueue.add(new AnimatorGroup(animators));
+ }
+ lastArray = copyArray(array);
+ }
+
+ public List getAnimationQueue() {
+ return animatorQueue;
+ }
+
+ private static int indexOf(int needle, int[] haystack) {
+ for (int i = 0; i < haystack.length; i++) {
+ if (haystack[i] == needle) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ private static int indexOf(T needle, T[] haystack) {
+ for (int i = 0; i < haystack.length; i++) {
+ if (haystack[i] != null && haystack[i].equals(needle)
+ || needle == null && haystack[i] == null) {
+ return i;
+ }
+ }
+ return -1;
+ }
+}
diff --git a/stream.iml b/stream.iml
index d5c0743..3891b2e 100644
--- a/stream.iml
+++ b/stream.iml
@@ -7,6 +7,8 @@
+
+
+
-
-
+
\ No newline at end of file