3. Problemin Tanımı
Oluşturulmuş bir veri havuzundan (yazı, ikilik data, veritabanında saklanan bir blok vs olabilir) verilen bir
şablonun elde edilmesi gerekmektedir. Bu tür işlemlerde elde bulunan veri kümesinden belirli özelliklere sahip
bir öğeyi bulmak adına arama algoritmaları kullanılır.
Arama Algortimaları
Bruteforce Search:
Algoritma işleyiş sırası şu şekildedir:
1. Yazıdan ve şablondan birer karakter al. Yazının sonuna gelindiyse 4. adıma geç.
2. Karakterler eşleşiyorsa 4. adıma git. Eşleşmiyorsa yazının bir sonraki karakteri, şablonun ise ilk
karkterini al ve 3. adımı tekrar et.
3. Şablonda bir sonraki karteri ve yazıdan bir sonraki karakteri al. Karakterler eşleşiyor ve şablonun
sonuna gelindiyse 4. adıma, şablon bitmemiş ise 2. adımdan devam et.
4. Bulunan index’i (bulunmadıysa yazının son index’i) ni belirlenen şekilde çıktıya bas.
En iyi
n*m
Ortalama
n*m
(Genel algoritma yapısı)
do
if (yazı karakteri== şablon karakteri)
bir sonraki karakterlere geç
else
yazıyı bir artır ve şablonun başındaki karakterden tekrar başla
while (yazının sonuna gelene kadar veya şablon bulunana kadar)
En kötü
n*m
4. Horspool Search:
Nigel Horspool tarafından 1980’lerde bulunmuştur. Yazı tabanlı bir algoritma olmakla birlikte BruteForce
algoritmasına nazaran uzun vadede daha performanslı bir algoritmadır.
En iyi
n
Ortalama
~n
En kötü
n*m
•
Aşağıdaki gibi bir karakter kaydırma değerlerinin bulunduğu bir tablo hazırlanır:
•
Şablon elimizdeki yazı içerisinde şablonun son karakterinden başlayarak karşılaştırırız, karakter
uyuşmazlığı oluşursa yazı içerisinden en son karşılaştırma yapmakta olduğumuz karakterin yukarıdaki
kaydırma değerlikleri tablosundaki değeri kadar kaydırma yaparız(şablon içerisinde yer almayan
karakterlerde şablon boyu kadar kaydırma gerçekleşir):
(Genel algoritma yapısı)
Horspool (P = p1p2…pm,T = t1t2…tn)
Ön İşleme
c ; d[c] ← m (karakter kaydırma değerliklerini şablonun boyutu olarak ata)
j ; 1…m-1 ; d[pj] ← m – j (şablon içerisinde yer alan karakterlerin right-most
değerliklerini bul, not: son karakter göz ardı edilir)
Arama
index←0
For index ≤ n-m Do
j ←m
for j > 0 ve (index +j) = p*j
Do j ← j-1
If j = 0 -> (index+1). konumda sonuç bulundu
index ← index +d[tpos+m]
For Sonu
7. Yazı Boyutu
10000000
10000000
10000000
10000000
10000000
10000000
10000000
10000000
10000000
10000000
10000000
10000000
10000000
10000000
10000000
10000000
10000000
10000000
10000000
10000000
Şablon Boyutu
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
BruteForce Eşleşen
Konum
8728844
9614302
8294439
7770644
8285835
9872020
9612393
9554464
8443063
8338894
8431209
9056025
8174466
7963535
7525507
8614163
9589647
8685110
9375489
7595301
BruteForce
Geçen Süre
23.997836
26.811422
23.162433
21.387457
22.852492
26.732911
26.128423
25.821049
23.362561
22.852492
22.93357
24.866082
22.633892
22.167955
20.973348
23.963455
26.58769
23.649409
25.935993
20.566422
Horspool
Eşleşen Konum
8728844
9614302
8294439
7770644
8285835
9872020
9612393
9554464
8443063
8338894
8431209
9056025
8174466
7963535
7525507
8614163
9589647
8685110
9375489
7595301
Horspool Geçen
Süre
12.528999
12.248308
11.153765
9.480392
10.3784
11.938367
15.833154
11.757739
12.015339
10.365571
12.720403
12.118482
10.285007
11.269223
11.210724
10.293217
13.713343
10.674486
10.733497
9.549155
Sonuç
BruteForce algoritması sürekli aynı karmaşıklıkta veri ararken, Horspool algoritması ilk aşamalarda yüksek
karmaşıklıkta arama yapmasının ardından yazı şablonunun boyutunun birkaç karakter artmasından sonra
yaklaşık %50 oranında daha az kaynak tüketimi ile daha performanslı olarak çalışmıştır.
8. Ekler
1. TestCase.java:
package com.hw02;
import java.util.HashMap;
import java.util.Map;
import
import
import
import
import
org.junit.After;
org.junit.Before;
org.junit.Rule;
org.junit.Test;
org.junit.rules.TestName;
public class TestCase {
AAlgorithm algorithm;
@Rule
public TestName name = new TestName(); // Çalıştırılan her algoritmanın adını almak için “Kural” tanımladık
public static char[] text; // Yazı ‘Main’ sınıfında oluşturuluyor
public static char[] pattern; // Yazı ‘Main’ sınıfında oluşturuluyor
public static Map<String, Double> map = new HashMap<String, Double>();
long start;
@Before
public void setUp() throws Exception { // burası her algoritma başlamadan önce çalışıyor
algorithm = createObject(Class.forName("com.hw02.algorithm." + name.getMethodName())); // Hangi
algoritma çalıştırılacağını belirledik
start = System.nanoTime(); // başlangıç saatini aldık
}
@After
public void tearDown() throws Exception { // burası her algoritma bitince çalışıyor
double duration = (System.nanoTime() - start) / 1000000D;
map.put(name.getMethodName(), duration);
}
@Test
public void BruteForce() {
exec();
}
@Test
public void Horspool() {
exec();
}
private void exec() {
try { // Elimizdek yazı içinde şablonu belirlenmiş algoritma ile çalıştırıyoruz ve bulunan index’i
saklıyoruz
map.put(name.getMethodName() + "_INDEX", Double.valueOf(algorithm.sort(text, pattern)));
}
catch (Exception e) {
e.printStackTrace(); // hata alırsak loga basıyoruz
}
}
kısım
public static AAlgorithm createObject(Class<?> klass) { // algoritmaların Sınıf’ı ile nesnesini oluşturan
try {
}
return (AAlgorithm) klass.newInstance();
}
catch (Exception e) {
e.printStackTrace();// Hata alırsak görmek adına loga basıyoruz
return null;
}
}
Main.java:
package com.hw02;
import
import
import
import
import
import
java.io.File;
java.io.FileNotFoundException;
java.io.PrintWriter;
java.io.UnsupportedEncodingException;
java.security.SecureRandom;
java.util.Arrays;
import org.junit.runner.JUnitCore;
9. public class Main {
private static SecureRandom random = new SecureRandom();
public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException {
int patternSize = 1; // Şablonun başlangıç boyutu
final int textSize = 10000000; // Yazı boyutu
final int MAX_PATTERN_SIZE = 100; // En fazla şablon boyutu
int startIndex; // Başlangıç konumu
char line = '0'; // ilk test çalıştırılmasında ilk başa “enter” basmayacağız sonrasında her test
çalıştırılmasından sonra
StringBuilder builder = new StringBuilder();
TestCase.text = generateArray(textSize);
for (; patternSize <= MAX_PATTERN_SIZE; patternSize++) {
startIndex = (TestCase.text.length / 4) * 3 + random.nextInt((TestCase.text.length / 4) patternSize);
// Şablonun yazıda olduğundan emin olmak adına,
// bi altta elimizdeki yazıyı 4’e böldüğümüzdeki son çeyreğinden örnek şablon aldık
TestCase.pattern = Arrays.copyOfRange(TestCase.text, startIndex, startIndex + patternSize);
JUnitCore.runClasses(TestCase.class); // Testi çalıştır
// Aşağıdaki gibi sırasıyla “TestCase” sınıfında oluşan test çıktılarını önbelleğe al
if (line == 'n')
builder.append(line);
builder.append(textSize);
builder.append('t'); // her bir veri kolonu arasına “tab” karakteri koyduk
builder.append(patternSize);
builder.append('t');
builder.append(TestCase.map.get("BruteForce_INDEX").intValue());
builder.append('t');
builder.append(TestCase.map.get("BruteForce"));
builder.append('t');
builder.append(TestCase.map.get("Horspool_INDEX").intValue());
builder.append('t');
builder.append(TestCase.map.get("Horspool"));
line = 'n';
TestCase.map.clear();
System.gc();
}
PrintWriter print = new PrintWriter(System.getProperty("user.home") + File.separator + "Desktop" +
File.separator + "out.txt", "UTF-8"); // Masaüstünde bir “out.txt” adında bir dosya oluşturduk
print.print(builder); // Testlerden elde ettiğimiz veriyi dosyaya yazdık
print.close(); // dosyayı kapattık
}
}
public static char[] generateArray(int size) {
char[] array = new char[size];
for (int i = size - 1, j = 0; i >= 0; i--, j++) {
array[j] = AAlgorithm.ALPHABET[random.nextInt(AAlgorithm.ALPHABET.length)];
}
return array;
}
AAlgorithm.java (Abstract Class):
package com.hw02;
public abstract class AAlgorithm {
public static final char[] ALPHABET = "abcçdefgğhıijklmnoöprsştuüvyz".toCharArray();
}
/**
* bulunan index’i döndürür
*/
public abstract int sort(char[] text, char[] pattern);
BruteForce.java:
package com.hw02.algorithm;
import com.hw02.AAlgorithm;
public class BruteForce extends AAlgorithm {
@Override
public int sort(char[] text, char[] pattern) {
10. int i, j;
for (i = 0, j = 0; i < text.length && j < pattern.length; i++) { // yazı boyutu kadar gitmeliyiz, şablon
boyutu kadar kontrol ettiysek demekki sonuca ulaşmışız.
if (text[i] == pattern[j]) // eşleşen karakter varsa bir sonrakini kontrol et
j++;
else {
i -= j;
j = 0;
}
}
if (j == pattern.length)
return i - pattern.length;
else
return -1;
}
}
Horspool.java:
package com.hw02.algorithm;
import com.hw02.AAlgorithm;
public class Horspool extends AAlgorithm {
private static int[] shiftTable = new int[ALPHABET.length];
@Override
public int sort(char[] text, char[] pattern) {
prepareTable(pattern); // kaydırma boyutlarının tutulduğu tabloyu oluştur
// şablonun boyutuyla başla
int i = pattern.length - 1, k;
// bulundu mu?
isMatch: while (i < text.length) {
k = i;
for (int j = pattern.length - 1; j >= 0; j--) {
if (pattern[j] == text[k]) {// karakter uyuşuyorsa bir sonrakine geç
k--;
continue;
}
else {
i += shiftTable[getCharIndex(text[i])]; // karakterin kaydırma değerliği
kadar kaydır
continue isMatch;
}
}
return k + 1; // yukarıdaki “for” döngüsünde eğer “j” sıfırandıysa buraya gelecek ve şablonun
tamamen eşleşmiş olduğu anlaşılacak, bu yüzden bulduğumuz konumu döndürüyoruz.
}
return -1;
}
public void prepareTable(char[] pattern) {
for (int i = 0; i < shiftTable.length; i++) {
shiftTable[i] = pattern.length; // ilk başta bütün karakter değerliklerini şablon byutu yap
}
for (char c : pattern) {
shiftTable[getCharIndex(c)] = shiftCount(c, pattern); // şablon karakterlerini sırasıyla
değerliklerini hesapla
}
}
private Integer shiftCount(char c, char[] pattern) {
for (int i = pattern.length - 2/* şablonun son karakterini yoksay */; i >= 0; i--) {
if (pattern[i] == c)
return pattern.length - 1 - i; // m-1-n formülüyle right-most index’i bul
}
return pattern.length;
}
}
public int getCharIndex(char i) { // karakterin alfabedeki konumunu bul
int j = 0;
for (char ch : ALPHABET) {
if (ch == i)
return j;
j++;
}
return -1;
}