“Algoritma Berkembang” atau Pengantar Algoritma yang Tidak Menyakitkan
Perkenalan
Hampir semua lowongan tingkat Junior memiliki persyaratan seperti “pengetahuan tentang struktur data dan algoritma.” Bagi mereka yang memiliki pendidikan khusus, algoritma termasuk dalam kursus umum dan seharusnya tidak ada masalah. Namun bagaimana jika pembangunan tersebut didatangkan dari stepa lain? Yang tersisa hanyalah belajar sendiri. Ada jawaban atas pertanyaan “siapa yang harus disalahkan”, tetapi untuk pertanyaan “apa yang harus dilakukan” jawabannya harus dicari. Mari kita lihat di buku. Dan saya ingin memberi tahu Anda tentang satu hal.Algoritma Grok
Di antara semua karya, saya menemukan buku seperti “Grocking Algorithms”. Anda dapat mengetahui lebih lanjut di sini: “ Buku “Algoritma Berkembang. Panduan bergambar untuk pemrogram dan mereka yang penasaran .” Saya sudah lama memperhatikan buku itu, tetapi untuk ozon harganya 680 rubel. Mahal atau murah - semua orang memutuskan sendiri. Saya sudah membeli buku kedua di Avito dengan setengah harga. Jadi saya menemukannya di St. Petersburg, membelinya, dan pergi mencarinya. Itulah yang saya putuskan untuk dibagikan kepada Anda. Ya, tidak ada kode Java di buku ini, tapi ada... kode lain, tapi akan dibahas lebih lanjut nanti.Pengantar Algoritma (Seleksi Sortir)
Jadi, dalam bentuk narasi yang mudah, kami mencapai penyortiran pertama dalam penampilan kami. Ini adalah Urutan Seleksi. Esensinya adalah kita menelusuri elemen dari kiri ke kanan (dari elemen 0 hingga terakhir), dan mencari yang terbesar di antara elemen yang tersisa. Jika kita menemukannya, maka kita menukar elemen tempat kita berada sekarang dan elemen terbesar. Cara paling sederhana untuk memikirkan sebuah array adalah: [5, 3, 6, 2, 10]. Ambil selembar kertas, pena (cara paling sederhana dan paling hemat biaya) dan bayangkan bagaimana kita memiliki batas kiri, indeks saat ini (atau batas kanan), dan indeks elemen minimum. Dan bagaimana kami mengatasinya. Misalnya:
def selectionSort(array):
for left in range(0, len(array)):
minIndex = left
for right in range (left+1, len(array)):
if array[right] < array[minIndex]:
minIndex = right
if minIndex != left:
temp = array[left]
array[left] = array[minIndex]
array[minIndex] = temp
return array
print(selectionSort([5, 3, 6, 2, 10]))
Sekarang mari kita sajikan dalam bentuk kode Java:
public static void selectionSort(int[] array) {
for (int left = 0; left < array.length; left++) {
int minIndex = left;
for (int right = left+1; right < array.length; right++) {
if (array[right] < array[minIndex]) {
minIndex = right;
}
}
if (minIndex != left) {
int temp = array[left];
array[left] = array[minIndex];
array[minIndex] = temp;
}
}
}
Seperti yang Anda lihat, kodenya hampir sama. Kode pertama adalah contoh dari buku. Yang kedua adalah eksekusi gratis saya dalam kode Java.
Pengulangan
Selanjutnya kita diberitahu bahwa ada yang namanya rekursi. Pertama, ada permasalahan pada seorang petani yang mempunyai lahan seluas AxB. Bidang ini perlu dibagi menjadi “kotak” yang sama. Dan kemudian setelah ini Algoritma Euclid disebutkan. Yang tidak saya sukai adalah mereka tidak mencoba menulis kodenya. Namun algoritma Euclid sederhana dan efektif:
def euclidean(a, b):
if a == 0 : return b
if b == 0 : return a
return euclidean (b, a % b)
Mari kita menulis kode yang sama di Java. Jika diinginkan, kita dapat menggunakan kompiler online :
public static int euclid(int a, int b) {
if (a == 0) return b;
if (b == 0) return a;
return euclid(b, a%b);
}
Faktorial juga disebutkan di awal buku. Faktorial suatu bilangan n (n!) adalah hasil kali bilangan dari 1 sampai n. Kenapa melakukan ini? Ada satu penerapan praktis di sini. Jika kita mempunyai n objek (misalnya n kota), maka kita dapat membuat n objek! Kombinasi. Anda dapat membaca lebih lanjut tentang rekursi di sini: " Rekursi. Tugas pelatihan ." Perbandingan pendekatan iteratif dan rekursif: " Rekursi ".
Penyortiran cepat
Penyortiran cepat adalah algoritma yang cukup menarik. Buku itu tidak terlalu memperhatikannya. Selain itu, kode tersebut hanya diberikan untuk kasus terburuk, ketika elemen pertama dipilih. Namun, mungkin bagi yang baru pertama kali mengenal contoh ini akan lebih mudah diingat. Dan lebih baik menulis quicksort yang buruk daripada tidak menulisnya sama sekali. Berikut ini contoh dari buku tersebut:
def quicksort(array):
if len(array) < 2:
return array
else:
pivot = array[0]
less = [i for i in array[1:] if i <= pivot]
greater = [i for i in array[1:] if i > pivot]
return quicksort(less) + [pivot] + quicksort(greater)
Semuanya di sini sangat sederhana. Jika kita memiliki array dengan elemen 0 atau 1, tidak perlu mengurutkannya. Jika lebih besar, kita mengambil elemen pertama dari array dan menganggapnya sebagai “elemen pivot”. Kami membuat 2 array baru - satu berisi elemen yang lebih besar dari pivot, dan yang kedua berisi elemen yang lebih kecil. Dan kami ulangi secara rekursif. Bukan pilihan terbaik, tapi sekali lagi, lebih baik diingat. Mari kita terapkan algoritma ini di Java, tetapi lebih tepat. Materi dari ulasan “ Ilmu Komputer dalam JavaScript: Quicksort ” akan membantu kami dalam hal ini . Dan sebelum menulis kodenya, mari kita menggambar lagi untuk “merasakan” algoritmanya: Pertama, mari kita menggambar lagi di selembar kertas untuk memahami algoritmanya:
-
Kita harus bisa menukar elemen dalam array:
private static void swap(int[] array, int firstIndex, int secondIndex) { int temp = array[firstIndex]; array[firstIndex] = array[secondIndex]; array[secondIndex] = temp; }
-
Kita memerlukan suatu metode yang membagi array pada interval yang ditentukan menjadi 3 bagian
private static int partition(int[] array, int left, int right) { int pivot = array[(right + left) / 2]; while (left <= right) { while (array[left] < pivot) { left++; } while (array[right] > pivot) { right--; } if (left <= right) { swap(array, left, right); left++; right--; } } return left; }
Detailnya ada di tautan di atas. Singkatnya, kita gerakkan kursor kiri hingga elemen tersebut kurang dari pivot. Demikian pula, gerakkan kursor kanan dari ujung yang lain. Dan kami melakukan swap jika kursor tidak cocok. Kami melanjutkan sampai kursor bertemu. Kami mengembalikan indeks yang membagi pemrosesan lebih lanjut menjadi 2 bagian.
-
Ada pemisahan, kita perlu penyortiran itu sendiri:
public static void quickSort(int[] array, int left, int right) { int index = 0; if (array.length > 1) { index = partition(array, left, right); if (left < index - 1) { quickSort(array, left, index - 1); } if (index < right) { quickSort(array, index, right); } } }
Artinya, jika array terdiri dari minimal dua elemen, maka elemen tersebut sudah dapat diurutkan. Pertama, kita membagi seluruh array menjadi dua bagian, elemen yang lebih kecil dari pivot dan elemen yang lebih besar. Kemudian kami melakukan tindakan serupa untuk setiap bagian yang dihasilkan.
Dan untuk ujiannya:
public static void main(String []args){ int[] array = {8,9,3,7,6,7,1}; quickSort(array, 0, array.length-1); System.out.println(Arrays.toString(array)); }
public static void mergeSort(int[] source, int left, int right) {
if ((right - left) > 1) {
int middle = (right + left) / 2;
mergeSort(source, left, middle);
mergeSort(source, middle + 1, right);
}
merge(source, left, right);
}
Kami menentukan bagian tengah dan membagi array menjadi dua. Untuk setiap bagian kami melakukan hal yang sama dan seterusnya. Kondisi penghentian atau kasus dasar - kita harus memiliki lebih dari satu elemen, karena kita tidak dapat membagi satu elemen menjadi dua. Sekarang kita perlu melaksanakan merger, yaitu merger:
public static void merge(int[] array, int from, int to) {
int middle = ((from + to) / 2) + 1;
int left = from;
int right = middle;
int cursor = 0;
int[] tmp = new int[to - from + 1];
while (left < middle || right <= to) {
if (left >= middle) {
tmp[cursor] = array[right];
System.out.println("Остаток справа: " + array[right]);
right++;
} else if (right > to) {
tmp[cursor] = array[left];
System.out.println("Остаток слева: " + array[left]);
left++;
} else if (array[left] <= array[right]) {
tmp[cursor] = array[left];
System.out.println("Слева меньше: " + array[left]);
left++;
} else if (array[right] < array[left]) {
tmp[cursor] = array[right];
System.out.println("Справа меньше: " + array[right]);
right++;
}
cursor++;
}
System.arraycopy(tmp, 0, array, from, tmp.length);
}
Tidak banyak yang bisa dikomentari di sini. Dari nama variabelnya println
semuanya jelas. Nah, untuk memeriksanya:
int array[] = {1, 7, 3, 6, 7, 9, 8, 4};
mergeSort(array, 0, array.length - 1);
System.out.println(Arrays.toString(array));
Tabel hash
Buku ini juga menyentuh tabel hash. Anda tidak perlu menerapkannya sendiri, dan inti dari tabel hash cukup sederhana. Lagipula, Java juga memiliki implementasi tabel hash, java.util.HashTable. Jika kita melihat perangkat HashTable, kita akan melihat bahwa array Entry ada di dalamnya. Entry merupakan record yang merupakan kombinasi Key – Value. HashTable memiliki InitialCapacity - yaitu ukuran awal. Dan loadFactor – faktor beban. Standarnya adalah 0,75. Angka ini memberi tahu Anda berapa beban array (jumlah elemen/jumlah total) yang ukurannya perlu ditingkatkan. Di Pulau Jawa meningkat 2 kali lipat. Buku tersebut menjelaskan bahwa tabel Hash disebut tabel hash karena berdasarkan fungsi hash, sel array (keranjang) di manaEntry
. Anda juga dapat membaca lebih lanjut di sini: Struktur data dalam gambar. HashMap dan LinkedHashMap . Anda juga bisa membacanya di buku. Misalnya di sini: " Dasar-dasar HashTable "
Grafik, Pencarian Pertama Luas (pencarian jalur terpendek)
Mungkin salah satu topik yang paling menarik adalah grafik. Dan di sini, sejujurnya, buku ini memberikan banyak perhatian kepada mereka. Mungkin itu sebabnya buku ini layak dibaca. Meskipun, mungkin, hal itu dapat dinyatakan dengan lebih jelas)) Namun, kami memiliki Internet dan selain buku, Anda dapat melihat daftar putar teori ini untuk “mereka yang baru pertama kali mendengar tentang grafik . ” Tentu saja, di awal buku ini, algoritma pencarian luas pertama,breadth-first-search
yang juga dikenal sebagai BFS, diberikan. Buku tersebut berisi grafik berikut:
private Map<String, String[]> getGraph() {
Map<String, String[]> map = new HashMap<>();
map.put("you", new String[]{"alice", "bob", "claire"});
map.put("bob", new String[]{"anuj", "peggy"});
map.put("alice", new String[]{"peggy"});
map.put("claire", new String[]{"thom", "jonny"});
map.put("annuj", null);
map.put("peggy", null);
map.put("thom", null);
map.put("johny", null);
return map;
}
Sekarang pencariannya sendiri, dibangun berdasarkan data ini:
private String search() {
Map<String, String[]> graph = getGraph();
Set<String> searched = new HashSet<>();
Deque<String> searchQue = new ArrayDeque<>();
searchQue.add("you");
while (!searchQue.isEmpty()) {
String person = searchQue.pollFirst();
System.out.println(person);
if (personIsSeller(person)) {
return person;
} else {
String[] friends = graph.get(person);
if (friends == null) continue;
for (String friend : friends) {
if (friend != null && !searched.contains(friend)) {
searchQue.addLast(friend);
}
}
}
}
return null;
}
Seperti yang Anda lihat, tidak ada yang rumit. Jika dibandingkan dengan kode yang ada di buku, hampir sama.
Grafik, Algoritma Dijkstra
Setelah kurang lebih memahami BFS, penulis buku ini mengajak kita untuk memahami algoritma Daysktra dan grafik berbobot. Grafik berikut diusulkan untuk solusinya:
public Integer[][] getGraphMatrix(int size) {
Integer[][] matrix = new Integer[size][size];
matrix[0][1] = 6;
matrix[0][2] = 2;
matrix[2][1] = 3;
matrix[1][3] = 1;
matrix[2][3] = 5;
return matrix;
}
Dan sekarang logikanya sendiri:
@Test
public void dijkstra() {
Integer[][] graph = getGraphMatrix(); // Данные графа
Integer[] costs = new Integer[graph.length]; // Стоимость перехода
Integer[] parents = new Integer[graph.length]; // Родительский узел
BitSet visited = new BitSet(graph.length); // "Ферма" маркеров посещённости
Integer w = 0;
do {
System.out.println("-> Рассматриваем вершину: " + w);
Integer min = null;
for (int i = 0; i < graph.length; i++) { // Обрабатываем каждую дугу
if (graph[w][i] == null) continue; // Дуги нет - идём дальше
if (min == null || (!visited.get(i) && graph[w][min] > graph[w][i])) {
min = i;
}
if (costs[i] == null || costs[i] > costs[w] + graph[w][i]) {
System.out.print("Меням вес с " + costs[i]);
costs[i] = (costs[w] != null ? costs[w] : 0) + graph[w][i];
System.out.println(" на " + costs[i] + " для вершины " + i);
parents[i] = w;
}
}
System.out.println("Вершина с минимальным весом: " + min);
visited.set(w);
w = min;
} while (w != null);
System.out.println(Arrays.toString(costs));
printPath(parents, 3);
}
public void printPath(Integer[] parents, int target) {
Integer parent = target;
do {
System.out.print(parent + " <- ");
parent = parents[parent];
} while (parent != null);
}
Buku ini menguraikannya langkah demi langkah. Jika Anda menambahkan artikel tentang Habré di Internet + melihat kodenya, Anda dapat mengingatnya. Menurut saya analisis langkah demi langkah agak berantakan. Tapi untuk sifat step by stepnya sendiri itu nilai plusnya. Secara keseluruhan, oke, meskipun bisa lebih baik)
Algoritma serakah
Bagian selanjutnya dikhususkan untuk "algoritma serakah". Bagian ini menarik karena menggunakan set (java.util.Set). Akhirnya kita dapat melihat mengapa hal itu mungkin diperlukan. Kami menggunakan daftar negara bagian sebagai masukan:
Set<String> statesNeeded = new HashSet();
statesNeeded.addAll(Arrays.asList("mt", "wa", "or", "id", "nv", "ut", "ca", "az" ));
Dan juga daftar stasiun radio yang meliput beberapa negara bagian ini:
Map<String, Set<String>> stations = new HashMap<>();
stations.put("kone", new HashSet(Arrays.asList("id", "nv", "ut")));
stations.put("ktwo", new HashSet(Arrays.asList("wa", "id", "mt")));
stations.put("kthree", new HashSet(Arrays.asList("or", "nv", "ca")));
stations.put("kfour", new HashSet(Arrays.asList("nv", "ut")));
stations.put("kfive", new HashSet(Arrays.asList("ca", "az")));
Buku ini selanjutnya menunjukkan dan menjelaskan algoritma itu sendiri:
Set<String> finalStations = new HashSet();
while (!statesNeeded.isEmpty()) {
String bestStation = null;
Set<String> statesCovered = new HashSet();
for (String station: stations.keySet()) {
Set covered = new HashSet(statesNeeded);
covered.retainAll(stations.get(station));
if (covered.size() > statesCovered.size()) {
bestStation = station;
statesCovered = covered;
}
}
statesNeeded.removeAll(statesCovered);
finalStations.add(bestStation);
}
System.out.println(finalStations);
Pemrograman dinamis
Buku ini juga menjelaskan permasalahan yang menggunakan pendekatan yang disebut “pemrograman dinamis”. Tugas yang diberikan:
List<Thing> things = new ArrayList<>();
things.add(new Thing("guitar", 1, 1500));
things.add(new Thing("tape recorder", 4, 3000));
things.add(new Thing("notebook", 3, 2000));
Sekarang algoritmanya sendiri:
int bagSize = 4;
int cell[][] = new int[things.size()][bagSize];
// Заполняем первую строку без условий
for (int i = 0; i < bagSize; i++) {
cell[0][i] = things.get(0).cost;
}
// Заполняем оставшиеся
for (int i = 1; i < cell.length; i++) {
for (int j = 0; j < cell[i].length; j++) {
// Если вещь не влезает - берём прошлый максимум
if (things.get(i).weight > j+1) {
cell[i][j] = cell[i - 1][j];
} else {
// Иначе текущая стоимость + предыдущий максимум оставшегося размера
cell[i][j] = things.get(i).cost;
if (j + 1 - things.get(i).weight > 0) {
cell[i][j] += cell[i-1][j + 1 - things.get(i).weight];
}
}
}
}
System.out.println(Arrays.deepToString(cell));
Ada juga tugas menarik untuk menemukan kata-kata yang paling mirip. Menarik bukan? Detail lebih lanjut di sini: LongestCommonSubsequence.java
Cari tetangga terdekat
Buku ini juga dengan jelas berbicara tentang algoritma k-nearest neighbours:Intinya
Buku ini diakhiri dengan bagian "Apa Selanjutnya?" yang menarik, yang memberikan gambaran singkat tentang algoritma yang menarik. Berikut ini penjelasan singkat mengenai pengertian pohon dan algoritma lainnya. Secara keseluruhan, saya menyukai buku itu. Ini tidak boleh dianggap serius sebagai informasi yang komprehensif. Anda harus mencari dan memahaminya sendiri. Namun sebagai informasi pengantar untuk menarik dan memberi gambaran awal, cukup bagus. Ya, kode di buku itu ditulis dengan Python. Jadi semua contoh di atas dapat dikompilasi) Saya harap ulasan ini dapat membantu Anda mendapatkan gambaran tentang isi buku tersebut dan apakah layak untuk dibeli.Selain itu
Anda juga dapat melihat sumber daya berikut tentang topik ini:- EdX - Pengantar Pemrograman Java: Struktur Data dan Algoritma Dasar
- LinkedIn - Pengantar Struktur Data & Algoritma di Java (berbayar)
- 27 situs dengan teka-teki untuk mempertajam keterampilan pemrograman Anda
- Pengodean JavaBat
- Tugas untuk programmer, jawaban atas tugas dengan kompleksitas yang berbeda-beda
GO TO FULL VERSION