JavaRush /Java Blog /Random-TK /Algoritmleri teoriýada we amaly taýdan tertiplemek
Viacheslav
Dereje

Algoritmleri teoriýada we amaly taýdan tertiplemek

Toparda çap edildi
Sortirlemek, obýektlerde ýerine ýetirilýän işleriň ýa-da hereketleriň esasy görnüşlerinden biridir. Çagalykda-da çagalara pikirlerini ösdürmek, tertiplemek öwredilýär. Kompýuterler we programmalar hem muňa degişli däldir. Algoritmleriň köp dürlüligi bar. Olaryň nämedigine we işleýşine göz aýlamagy maslahat berýärin. Mundan başga-da, bir gün söhbetdeşlikde bularyň biri hakda soralsa näme etmeli?
Algoritmleri teoriýada we amaly taýdan tertiplemek - 1

Giriş

Elementleri tertiplemek, işläp düzüjiniň öwrenişmeli algoritmleriniň kategoriýalaryndan biridir. Bir wagtlar okaýan wagtym kompýuter bilimine beýle çynlakaý garalmaýan bolsa, indi mekdepde tertipleşdirmek algoritmlerini durmuşa geçirmeli we olara düşünmeli. Esasy algoritmler, iň ýönekeýleri, aýlaw arkaly amala aşyrylýar for. Elbetde, elementleriň ýygyndysyny tertiplemek üçin, mysal üçin bir massiw, bu ýygyndydan nähilidir bir geçmeli. Mysal üçin:
int[] array = {10, 2, 10, 3, 1, 2, 5};
for (int i = 0; i < array.length; i++) {
	System.out.println(array[i]);
}
Bu kod bölegi barada näme aýdyp bilersiňiz? int iIndeks bahasyny ( ) 0-dan massiwdäki iň soňky elemente üýtgedýän aýlawymyz bar . Aslynda, her elementi massiwde alyp, mazmunyny çap edýäris. Toplumda näçe köp element bar bolsa, kod ýerine ýetirmek üçin şonça köp wagt alar. .Agny, n elementleriň sany bolsa, n = 10 bilen programma n = 5 bilen deňeşdirilende 2 esse köp wagt alar. Haçan-da programmamyzda bir aýlaw bar bolsa, ýerine ýetiriş wagty çyzykly artýar: näçe köp element bolsa, ýerine ýetiriş şonça-da uzyn bolýar. Görnüşi ýaly, ýokardaky koduň algoritmi çyzykly wagtda (n) işleýär. Şeýle ýagdaýlarda “algoritm çylşyrymlylygy” O (n) diýilýär. Bu düşünje "uly O" ýa-da "asimptotik hereket" diýilýär. Emma “algoritmiň çylşyrymlylygyny” ýadyňyzda saklap bilersiňiz.
Algoritmleri teoriýada we amaly taýdan tertiplemek - 2

Iň ýönekeý tertipleşdirme (Bubble Sort)

Şeýlelik bilen, bir massiwimiz bar we onuň üstünde gaýtalap bileris. Gowy. Geliň indi ony ýokaryk tertipleşdirmäge synanyşalyň. Bu biziň üçin nämäni aňladýar? Diýmek, iki element berilýär (mysal üçin, a = 6, b = 5), eger a b b-den uly bolsa (a> b) bolsa a we b çalyşmaly. Indeks boýunça kolleksiýa bilen işlänimizde (bir massiwdäki ýaly) bu biziň üçin nämäni aňladýar? Diýmek, a indeksli element b indeksli elementden uly bolsa, (massiw [a]> massiw [b]), şonuň ýaly elementler çalşylmalydyr. Placeserleri üýtgetmek köplenç swap diýilýär. Placeserleri üýtgetmegiň dürli ýollary bar. Emma kody ýönekeý, düşnükli we ýatda saklamak aňsat ulanýarys:
private void swap(int[] array, int ind1, int ind2) {
    int tmp = array[ind1];
    array[ind1] = array[ind2];
    array[ind2] = tmp;
}
Indi aşakdakylary ýazyp bileris:
int[] array = {10, 2, 10, 3, 1, 2, 5};
System.out.println(Arrays.toString(array));
for (int i = 1; i < array.length; i++) {
	if (array[i] < array[i - 1]) {
		swap(array, i, i-1);
	}
}
System.out.println(Arrays.toString(array));
Görşümiz ýaly elementler hakykatdanam ýerleri üýtgedi. Bir element bilen başladyk, sebäbi ... eger massiw diňe bir elementden ybarat bolsa, 1 <1 aňlatmasy hakykata gaýdyp gelmez we şeýlelik bilen özümizi bir elementli ýa-da olarsyz massiw ýagdaýlaryndan gorarys we kod has gowy görüner. Finalöne soňky massiwimiz her niçigem bolsa tertiplenenok, sebäbi ... Hemmäni bir pasda tertiplemek mümkin däl. Başga bir aýlaw goşmaly bolarys, onda tertipli massiw alýançam birin-birin geçeris:
int[] array = {10, 2, 10, 3, 1, 2, 5};
System.out.println(Arrays.toString(array));
boolean needIteration = true;
while (needIteration) {
	needIteration = false;
	for (int i = 1; i < array.length; i++) {
		if (array[i] < array[i - 1]) {
			swap(array, i, i-1);
			needIteration = true;
		}
	}
}
System.out.println(Arrays.toString(array));
Şeýlelik bilen ilkinji sortlaşdyryşymyz işledi. whileMundan beýläk gaýtalamagyň zerur däldigini kesgitleýänçäk, daşarky aýlawda () gaýtalaýarys . Düzgüne görä, her täze gaýtalanmazdan ozal, massiwimiziň tertiplenendigini çaklaýarys we mundan beýläk gaýtalamak islemeýäris. Şonuň üçin elementleri yzygiderli öwrenýäris we bu çaklamany barlaýarys. Emma elementler tertipsiz bolsa, elementleri çalyşýarys we elementleriň häzirki tertipde bolandygyna ynanmaýarys. Şonuň üçin ýene bir gezek gaýtalamak isleýäris. Mysal üçin, [3, 5, 2]. 5 üçden köp, hemme zat gowy. 2öne 5-den az. Şeýle-de bolsa, [3, 2, 5] ýene bir pas talap edýär, sebäbi 3> 2 we olary çalyşmaly. Bir aýlawyň içinde aýlaw ulanýandygymyz sebäpli, algoritmimiziň çylşyrymlylygy ýokarlanýar. N elementleri bilen n * n bolýar, ýagny O (n ^ 2). Bu çylşyrymlylyga kwadrat diýilýär. Düşünşimiz ýaly, näçe gaýtalamagyň zerurdygyny anyk bilip bilmeris. Algoritm çylşyrymlylygy görkezijisi, iň erbet ýagdaý çylşyrymlylygyň ýokarlanmagyny görkezmek maksadyna hyzmat edýär. N elementleriň sany üýtgese, iş wagty näçe artar. Köpürjik görnüşi iň ýönekeý we netijesiz görnüşleriň biridir. Kämahal "samsyk sortlamak" hem diýilýär. Degişli material:
Algoritmleri teoriýada we amaly taýdan tertiplemek - 3

Saýlama tertibi

Başga bir görnüş, saýlama görnüşi. Şeýle hem kwadrat çylşyrymlylygy bar, ýöne has soňrak. Şonuň üçin pikir ýönekeý. Her geçiş iň kiçi elementi saýlaýar we başyna geçirýär. Bu ýagdaýda her täze geçişi saga, ýagny birinji geçişden - birinji elementden, ikinji geçişden - ikinjiden başlaň. Bu şeýle bolar:
int[] array = {10, 2, 10, 3, 1, 2, 5};
System.out.println(Arrays.toString(array));
for (int left = 0; left < array.length; left++) {
	int minInd = left;
	for (int i = left; i < array.length; i++) {
		if (array[i] < array[minInd]) {
			minInd = i;
		}
	}
	swap(array, left, minInd);
}
System.out.println(Arrays.toString(array));
Bu sortlamak durnuksyz, sebäbi meňzeş elementler (elementleri tertipleşdirýän häsiýet nukdaýnazaryndan) olaryň ýagdaýyny üýtgedip biler. Wikipediýa makalasynda gowy mysal berilýär: Sorting_by-selection . Degişli material:
Algoritmleri teoriýada we amaly taýdan tertiplemek - 4

Goýmak tertibi

Goýmak görnüşi hem kwadratiki çylşyrymlylyga eýe, sebäbi bizde ýene bir aýlaw bar. Saýlaw görnüşinden nähili tapawutlanýar? Bu sortlaşdyrma "durnukly". Bu birmeňzeş elementleriň tertibini üýtgetmejekdigini aňladýar. Saýlaýan aýratynlyklarymyz taýdan birmeňzeş.
int[] array = {10, 2, 10, 3, 1, 2, 5};
System.out.println(Arrays.toString(array));
for (int left = 0; left < array.length; left++) {
	// Retrieve the value of the element
	int value = array[left];
	// Move through the elements that are before the pulled element
	int i = left - 1;
	for (; i >= 0; i--) {
		// If a smaller value is pulled out, move the larger element further
		if (value < array[i]) {
			array[i + 1] = array[i];
		} else {
			// If the pulled element is larger, stop
			break;
		}
	}
	// Insert the extracted value into the freed space
	array[i + 1] = value;
}
System.out.println(Arrays.toString(array));
Degişli material:
Algoritmleri teoriýada we amaly taýdan tertiplemek - 5

Shuttle Sort

Simpleönekeý görnüşleriň arasynda başga biri bar - gatnawy sortlamak. Shöne men gatnaw görnüşini has gowy görýärin. Meniň pikirimçe, kosmos gatnawlary hakda seýrek gürleşýäris we gatnaw has köp işleýär. Şol sebäpli, kosmosda gatnawlaryň nädip uçulandygyny göz öňüne getirmek has aňsat. Ine, bu algoritm bilen baglanyşyk. Algoritmiň manysy näme? Algoritmiň düýp manysy, çepden saga gaýtalanmagymyzdyr we elementleri çalşanymyzda çalşygyň gaýtalanmalydygyny ýa-da ýokdugyny bilmek üçin yzda galan beýleki elementleri barlaýarys.
int[] array = {10, 2, 10, 3, 1, 2, 5};
System.out.println(Arrays.toString(array));
for (int i = 1; i < array.length; i++) {
	if (array[i] < array[i - 1]) {
		swap(array, i, i - 1);
		for (int z = i - 1; (z - 1) >= 0; z--) {
			if (array[z] < array[z - 1]) {
				swap(array, z, z - 1);
			} else {
				break;
			}
		}
	}
}
System.out.println(Arrays.toString(array));
Degişli material:
Algoritmleri teoriýada we amaly taýdan tertiplemek - 6

Gabyk görnüşi

Anotherene bir ýönekeý görnüş “Shell sort”. Onuň düýp manysy köpürjik görnüşine meňzeýär, ýöne her gezek gaýtalanylanda deňeşdirilýän elementleriň arasynda tapawutly boşluk bar. Her gezek gaýtalama ýarym bolýar. Ine, durmuşa geçirmegiň mysaly:
int[] array = {10, 2, 10, 3, 1, 2, 5};
System.out.println(Arrays.toString(array));
// Calculate the gap between the checked elements
int gap = array.length / 2;
// As long as there is a difference between the elements
while (gap >= 1) {
    for (int right = 0; right < array.length; right++) {
        // Shift the right pointer until we can find one that
        // there won't be enough space between it and the element before it
       for (int c = right - gap; c >= 0; c -= gap) {
           if (array[c] > array[c + gap]) {
               swap(array, c, c + gap);
           }
        }
    }
    // Recalculate the gap
    gap = gap / 2;
}
System.out.println(Arrays.toString(array));
Degişli material:
Teoriýada we amaly taýdan algoritmleri tertiplemek - 7

Birleşdiriň

Görkezilen ýönekeý görnüşlerden başga-da has çylşyrymly görnüşler bar. Mysal üçin, görnüşi birleşdiriň. Ilki bilen gaýtalanma kömegimize geler. Ikinjiden, çylşyrymlylygymyz öňküsi ýaly dörtburç bolmaz. Bu algoritmiň çylşyrymlylygy logarifmikdir. O (n log n) görnüşinde ýazylan. Geliň, muny edeliň. Ilki bilen, tertipleşdiriş usulyna gaýtalanýan jaň ýazalyň:
public static void mergeSort(int[] source, int left, int right) {
        // Choose a separator, i.e. split the input array in half
        int delimiter = left + ((right - left) / 2) + 1;
        // Execute this function recursively for the two halves (if we can split(
        if (delimiter > 0 && right > (left + 1)) {
            mergeSort(source, left, delimiter - 1);
            mergeSort(source, delimiter, right);
        }
}
Indi, oňa esasy bir hereket goşalyň. Ine, durmuşa geçirmek bilen supermetodymyzyň mysaly:
public static void mergeSort(int[] source, int left, int right) {
        // Choose a separator, i.e. split the input array in half
        int delimiter = left + ((right - left) / 2) + 1;
        // Execute this function recursively for the two halves (if we can split(
        if (delimiter > 0 && right > (left + 1)) {
            mergeSort(source, left, delimiter - 1);
            mergeSort(source, delimiter, right);
        }
        // Create a temporary array with the desired size
        int[] buffer = new int[right - left + 1];
        // Starting from the specified left border, go through each element
        int cursor = left;
        for (int i = 0; i < buffer.length; i++) {
            // We use the delimeter to point to the element from the right side
            // If delimeter > right, then there are no unadded elements left on the right side
            if (delimiter > right || source[cursor] > source[delimiter]) {
                buffer[i] = source[cursor];
                cursor++;
            } else {
                buffer[i] = source[delimiter];
                delimiter++;
            }
        }
        System.arraycopy(buffer, 0, source, left, buffer.length);
}
Geliň, mysaly çagyryp işledeliň mergeSort(array, 0, array.length-1). Görşüňiz ýaly, mazmuny tertipleşdirilmeli bölümiň başyny we soňuny görkezýän bir massiw hökmünde kabul edýäris. Saýlamak başlanda, bu massiwiň başlangyjy we ahyry. Ondan soň delimiter - bölüjiniň ýagdaýyny hasaplaýarys. Eger bölüji 2 bölege bölüp bilýän bolsa, bölüjiniň massiwini bölen bölümleri üçin gaýtalanýan tertipleşdirme diýýäris. Saýlanan bölümi saýlaýan goşmaça bufer massiwini taýýarlaýarys. Ondan soň, kursory tertipleşdirmek üçin meýdançanyň başynda goýýarys we taýýarlan boş massiwiň her elementinden geçip, iň kiçi elementler bilen doldurýarys. Kursor bilen görkezilen element bölüjiniň görkezen elementinden has kiçi bolsa, bu elementi bufer massiwine ýerleşdirýäris we kursory süýşürýäris. Otherwiseogsam, bölüjiniň görkezen elementini bufer massiwine ýerleşdirýäris we bölüjini süýşürýäris. Aýyryjy sortlanan meýdanyň çäklerinden çyksa ýa-da tutuş massiwini dolduranymyzdan soň, görkezilen aralyk tertipleşdirilen hasaplanýar. Degişli material:
Algoritmleri teoriýada we amaly taýdan tertiplemek - 8

Sort we Radix Sort sanamak

Anotherene-de bir gyzykly sortlaşdyryş algoritmi “Counting Sort”. Bu ýagdaýda algoritmiki çylşyrymlylyk O (n + k) bolar, bu ýerde n elementleriň sany, k bolsa elementiň iň ýokary bahasydyr. Algoritmde bir mesele bar: massiwdäki iň pes we iň ýokary bahalary bilmeli. Ine, sanamagyň görnüşini durmuşa geçirmegiň mysaly:
public static int[] countingSort(int[] theArray, int maxValue) {
        // Array with "counters" ranging from 0 to the maximum value
        int numCounts[] = new int[maxValue + 1];
        // In the corresponding cell (index = value) we increase the counter
        for (int num : theArray) {
            numCounts[num]++;
        }
        // Prepare array for sorted result
        int[] sortedArray = new int[theArray.length];
        int currentSortedIndex = 0;
        // go through the array with "counters"
        for (int n = 0; n < numCounts.length; n++) {
            int count = numCounts[n];
            // go by the number of values
            for (int k = 0; k < count; k++) {
                sortedArray[currentSortedIndex] = n;
                currentSortedIndex++;
            }
        }
        return sortedArray;
    }
Düşünşimiz ýaly, iň pes we iň ýokary bahalary öňünden bilmeli bolanymyzda gaty amatsyz. Soň bolsa başga bir algoritm bar - Radix Sort. Algoritmi bu ýerde diňe wizual görkezerin. Durmuşa geçirmek üçin materiallara serediň:
Algoritmleri teoriýada we amaly taýdan tertiplemek - 9
Materiallar:
Algoritmleri teoriýada we amaly taýdan tertiplemek - 10

Java Çalt Sort

Dogrusy, desert üçin - iň meşhur algoritmleriň biri: çalt sortlamak. Algoritmiki çylşyrymlylygy bar, ýagny O (n log n) bar. Bu görnüşe Hoare sorty hem diýilýär. Gyzykly tarapy, algoritm Hoare Sowet Soýuzynda bolan döwründe oýlanyp tapyldy we Moskwa uniwersitetinde kompýuter terjimesini öwrendi we rus-iňlis söz düzümini taýýarlady. Bu algoritm Java-daky Arrays.sort-da has çylşyrymly durmuşa geçirilende ulanylýar. Kolleksiýalar.sort hakda näme? Olaryň “kapotyň aşagynda” nähili tertipleşdirilendigini özüňiz görmegiňizi maslahat berýärin. Şeýlelikde, kod:
public static void quickSort(int[] source, int leftBorder, int rightBorder) {
        int leftMarker = leftBorder;
        int rightMarker = rightBorder;
        int pivot = source[(leftMarker + rightMarker) / 2];
        do {
            // Move the left marker from left to right while element is less than pivot
            while (source[leftMarker] < pivot) {
                leftMarker++;
            }
            // Move the right marker until element is greater than pivot
            while (source[rightMarker] > pivot) {
                rightMarker--;
            }
            // Check if you don't need to swap elements pointed to by markers
            if (leftMarker <= rightMarker) {
                // The left marker will only be less than the right marker if we have to swap
                if (leftMarker < rightMarker) {
                    int tmp = source[leftMarker];
                    source[leftMarker] = source[rightMarker];
                    source[rightMarker] = tmp;
                }
                // Move markers to get new borders
                leftMarker++;
                rightMarker--;
            }
        } while (leftMarker <= rightMarker);

        // Execute recursively for parts
        if (leftMarker < rightBorder) {
            quickSort(source, leftMarker, rightBorder);
        }
        if (leftBorder < rightMarker) {
            quickSort(source, leftBorder, rightMarker);
        }
}
Bu ýerdäki hemme zat gaty gorkunç, şonuň üçinem öwreneris. Giriş massiwiniň int[]çeşmesi üçin çep (L) we sag (R) iki marker goýýarys. Ilkinji gezek çagyrylanda, massiwiň başyna we soňuna gabat gelýär. Ondan soň, goldaýan element kesgitlenýär pivot. pivotOndan soň biziň wezipämiz bahalary çepe pivot, has ulusyny bolsa saga geçirmekdir . Munuň üçin ilki bilen Lhas uly bahany tapýançak görkezijini süýşüriň pivot. Eger has kiçi baha tapylmasa, onda L совпадёт с pivot. Потом двигаем указатель R пока не найдём меньшее, чем pivot meaning. Если меньшее meaning не нашли, то R совпадёт с pivot. Далее, если указатель L находится до указателя R or совпадает с ним, то пытаемся выполнить обмен элементов, если элемент L меньше, чем R. Далее L сдвигаем вправо на 1 позицию, R сдвигаем влево на одну позицию. Когда левый маркер L окажется за правым маркером R это будет означать, что обмен закончен, слева от pivot меньшие значения, справа от pivot — большие значения. После этого рекурсивно вызываем такую же сортировку для участков массива от начала сортируемого участка до правого маркера и от левого маркера до конца сортируемого участка. Почему от начала до правого? Потому что в конце итерации так и получится, что правый маркер сдвинется настолько, что станет границей части слева. Этот алгоритм более сложный, чем простая sorting, поэтому его лучше зарисовать. Возьмём белый лист бумаги, запишем: 4 2 6 7 3 , а Pivot по центру, т.е. число 6. Обведём его в круг. Под 4 напишем L, под 3 напишем R. 4 меньше чем 6, 2 меньше чем 6. Total, L переместился на положение pivot, т.к. по условию L не может уйти дальше, чем pivot. Напишем снова 4 2 6 7 3 , обведём 6 вкруг ( pivot) и поставим под ним L. Теперь двигаем указатель R. 3 меньше чем 6, поэтому ставим маркер R на цифру 3. Так How 3 меньше, чем pivot 6 выполняем swap, т.е. обмен. Запишем результат: 4 2 3 7 6 , обводим 6 вкруг, т.к. он по прежнему pivot. Указатель L на цифре 3, указатель R на цифре 6. Мы помним, что двигаем указатели до тех пор, пока L не зайдём за R. L двигаем на следующую цифру. Тут хочется разобрать два варианта: если бы предпоследняя цифра была 7 и если бы она была не 7, а 1. Предпоследня цифра 1: Сдвинули указатель L на цифру 1, т.к. мы можем двигать L до тех пор, пока указатель L указывает на цифру, меньшую чем pivot. А вот R мы не можем сдвинуть с 6, т.к. R не мы можем двигать только если указатель R указывает на цифру, которая больше чем pivot. swap не делаем, т.к. 1 меньше 6. Записываем положение: 4 2 3 1 6, обводим pivot 6. L сдвигается на pivot и больше не двигается. R тоже не двигается. Обмен не производим. Сдвигаем L и R на одну позицию и подписываем цифру 1 маркером R, а L получается вне числа. Т.к. L вне числа — ничего не делаем, а вот часть 4 2 3 1 выписываем снова, т.к. это наша левая часть, меньшая, чем pivot 6. Выделяем новый pivot и начинаем всё снова ) Предпоследняя цифра 7: Сдвинули указать L на цифру 7, правый указатель не можем двигать, т.к. он уже указывает на pivot. т.к. 7 больше, чем pivot, то делаем swap. Запишем результат: 4 2 3 6 7, обводим 6 кружком, т.к. он pivot. Указатель L теперь сдвигается на цифру 7, а указатель R сдвигается на цифру 3. Часть от L до конца нет смысла сортировать, т.к. там всего 1 элемент, а вот часть от 4 до указателя R отправляем на сортировку. Выбираем pivot и начинаем всё снова ) Может на первый взгляд показаться, что если расставить много одинаковых с pivot значений, это сломает алгоритм, но это не так. Можно напридумывать каверзных вариантов и на бумажке убедиться, что всё правильно и подивиться, How такие простые действия предоставляют такой надёжный механизм. Единственный минус — такая sorting не является стабильной. Т.к. при выполнении обмена одинаковые элементы могут поменять свой порядок, если один из них встретился до pivot до того, How другой элемент попал в часть до pivot при помощи обмена. Материал:

Итог

Выше мы рассмотрели "джентельменский" набор алгоритмов сортировки, реализованных на Java. Алгоритмы вообще штука полезная, How с прикладной точки зрения, так и с точки зрения развития мышления. Некоторые из них попроще, некоторые посложнее. По Howим-то умные люди защищали различные работы на степени, а по другим писали толстые-толстые книги. Надеюсь, приложенный к статье материал позволит вам узнать ещё больше, так How это обзорная статья, которая и так получилась увесистой. И цель её — дать небольшое вступление. Про введение в алгоритмы можно так же прочитать ознакомиться с книгой " Грокаем Алгоримы". Также мне нравится плэйлист от Jack Brown — AQA Decision 1 1.01 Tracing an Algorithm. Ради интереса можно посмотреть на визуализацию алгоритмов на sorting.at и visualgo.net. Ну и весь Youtube к вашим услугам.
Teswirler
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION