Bir Şifreyi Rastgele mi Yoksa Sıra İle mi Denemek Daha Hızlıdır?
Selamlar,
Bu makalede aklıma takılan bir soruya daha doğrusu merak ettiğim bir konuya, hep beraber cevap arayacağız :)
Soru : Diyelim ki 6 haneli bir Şifreyi bulmak gereksin. 2 yöntemimiz olsun.
- Klasik 1’den 999999’a kadar tüm şifreler, tek tek denenir.
- Yol ise çok farklı. Öncelikle 6 haneli olabilecek tüm sayılar bir diziye toplanır. Daha sonra listeden random 1 sayı çekilir. Şifreye ulaşılamaz ise ilgili sayı listeden çıkarılıp, random yeni bir sayı çekilir. Bu işleme, şifre bulunana kadar devam edilir.
Bilin bakalım hangi işlem daha kısa sürer ?
FindByCount(): Bu method, klasik 6 haneli tüm sayıları iç içe 6 döngü ile gezmekte ve şifre bulunduğunda geri dönmektedir. Örneğin 999999 password’ü için, tüm olasılıklar denenmektedir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public static string FindByCount(int password) { for (var a = 0; a < 10; a++) for (var b = 0; b < 10; b++) for (var c = 0; c < 10; c++) for (var d = 0; d < 10; d++) for (var e = 0; e < 10; e++) for (var f = 0; f < 10; f++) { Console.WriteLine(f.ToString() + e.ToString() + d.ToString() + c.ToString() + b.ToString() + a.ToString()); if (password.ToString() == (f.ToString() + e.ToString() + d.ToString() + c.ToString() + b.ToString() + a.ToString())) { return (f.ToString() + e.ToString() + d.ToString() + c.ToString() + b.ToString() + a.ToString()); } } return ""; } |
FillArray() : 6 haneli tüm sayılar, bir dizi içerisine 6 döngü ile string olarak atılmıştır. Burada amaç, 6 haneli şifre olabilecek tüm sayıların önceden bulunup bir listede tutulmasıdır.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public static void FillArray() { listOfPassword = new List<string>(); for (var a = 0; a < 10; a++) for (var b = 0; b < 10; b++) for (var c = 0; c < 10; c++) for (var d = 0; d < 10; d++) for (var e = 0; e < 10; e++) for (var f = 0; f < 10; f++) { listOfPassword.Add(f.ToString() + e.ToString() + d.ToString() + c.ToString() + b.ToString() + a.ToString()); } } |
FindByRandom(): Bu methodda amaç, 6 haneli bir şifrenin tüm olasılıklarının bulunduğu bir diziden rastgele bir sayının çekilmesi, ve doğru değil ise ilgili sayının listeden çıkarılıp aynı işlemin şifre bulunana kadar tekrarlanmasıdır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public static string FindByRandom(int password) { Random rnd = new Random(); while (listOfPassword.Count > 0) { int index = rnd.Next(listOfPassword.Count); if (password.ToString() == listOfPassword[index]) { return listOfPassword[index]; } else { Console.WriteLine(listOfPassword[index]); listOfPassword.RemoveAt(index); Console.WriteLine("listOfPassword Count:" + listOfPassword.Count.ToString()); } } return ""; } |
Aşağıda örnek amaçlı yapılmış 2 deneme görülmektedir. Açık ara fark ile, sıralı sayım yöntemi yani FindByCount() çok daha hızlı sonuca ulaşmaktadır.
Böylece geldik bir makalenin daha sonuna. Bu makalede, rastgele seçim yöntemi mi yoksa sıralı deneme yöntemi mi daha hızlı Myth’ine bir cevap bulmaya çalıştık. Random deneme biraz şansa bir durum gibi gözükse de, sıralı deneme benim gibi sağlamcı developerlar için açık ara en iyi yöntem :)
Yeni bir makalede görüşmek üzere hepinize hoşçakalın.
Tüm Kod:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
using System; using System.Collections.Generic; namespace password { class Program { static void Main(string[] args) { GetPassword(); } public static void GetPassword() { FillArray(); Console.Write("Password ? Only Number And 6 Digit..:"); int password; var result = int.TryParse(Console.ReadLine(), out password); if (!result || (result && password.ToString().Length != 6)) { GetPassword(); } Console.WriteLine("1-)Random"); Console.WriteLine("2-)ByCount:"); if (int.TryParse(Console.ReadLine(), out int type)) { switch (type) { case 1: { var start = DateTime.Now; var resultPassword = FindByRandom(password); var end = DateTime.Now; TimeSpan totlaTime = end - start; Console.WriteLine($"Thank You! I Found Password is {resultPassword}....In {totlaTime.TotalSeconds} seconds"); GetPassword(); break; } case 2: { var start = DateTime.Now; var resultPassword = FindByCount(password); var end = DateTime.Now; TimeSpan totlaTime = end - start; Console.WriteLine($"Thank You! I Found Password is {resultPassword}....In {totlaTime.TotalSeconds} seconds"); GetPassword(); break; } } } } public static string FindByCount(int password) { for (var a = 0; a < 10; a++) for (var b = 0; b < 10; b++) for (var c = 0; c < 10; c++) for (var d = 0; d < 10; d++) for (var e = 0; e < 10; e++) for (var f = 0; f < 10; f++) { Console.WriteLine(f.ToString() + e.ToString() + d.ToString() + c.ToString() + b.ToString() + a.ToString()); if (password.ToString() == (f.ToString() + e.ToString() + d.ToString() + c.ToString() + b.ToString() + a.ToString())) { return (f.ToString() + e.ToString() + d.ToString() + c.ToString() + b.ToString() + a.ToString()); } } return ""; } static List<string> listOfPassword; public static void FillArray() { listOfPassword = new List<string>(); for (var a = 0; a < 10; a++) for (var b = 0; b < 10; b++) for (var c = 0; c < 10; c++) for (var d = 0; d < 10; d++) for (var e = 0; e < 10; e++) for (var f = 0; f < 10; f++) { listOfPassword.Add(f.ToString() + e.ToString() + d.ToString() + c.ToString() + b.ToString() + a.ToString()); } } public static string FindByRandom(int password) { Random rnd = new Random(); while (listOfPassword.Count > 0) { int index = rnd.Next(listOfPassword.Count); if (password.ToString() == listOfPassword[index]) { return listOfPassword[index]; } else { Console.WriteLine(listOfPassword[index]); listOfPassword.RemoveAt(index); Console.WriteLine("listOfPassword Count:" + listOfPassword.Count.ToString()); } } return ""; } } } |
Çok ilginç yazı olmuş. Ellerinize sağlık :)
tek bir denemeden bu sonuca nasıl ulaştınız? yüz adet test yapıp mod yada aritmetik ortalamayı paylaşmak daha sağlıklı olacaktır.
Selamlar Ali,
Siz bir selenium ile autotest yazıp, aynı işlemi 1000 kere farklı şifreler ile denetip makalenin sonuna yorum olarak paylaşırsanız harika olur :) Nerde hareket orda bereket :)
İyi çalışmalar.
Güzel asist, güzel gol :)
Random şifre aramaya haksızlık olmuş. List bir siniftan remove etme işlemi ile de zaman kaybedilir olabilir. Hashset ve dictionary ile de denemek lazım. Adil olması için sıralı aramada da tumunu listeye atıp her denediginde remove etmek lazım belkide… İlk aklıma bu geldi ama belki yanlış düşündüm bir an:) güzel çalışma ama fark büyük olduğu için bir sıkıntı var gibi geldi nedense bana.
Selam Çetin,
Güzel fikir! Onu da hangimiz önce dener ise bu yorumun altına sonucu atsın !
Burada new Random() satırı da yavaşlamaya sebep olmuş olabilir mi ? Yani Random sayı üretmek maliyetli olduğundan da böyle bir sonuca ulaşmış olabilir mi ?
Selam Hakan,
Burada şu kısım, “int index = rnd.Next(listOfPassword.Count);” maliyetli olabilir.
Varyasyon Listini parçalara bölüp her bir parçayı bir ayrı threadde yesek Randoma yeterli nitroyu vermiş olur muyuz ? Verdiğimiz hız tükettiğimiz kaynağa değer mi ? Babam pasta yapmayı neden öğrenmedi ?
Olmayız :)
Çok bilgilendiricibir yazı.
Teşekkürler.
Hocam çok muazzam bir anlatım elinize sağlık
Teşekkürler..
üstat bu yazı ilginç ama çıkarım da bir hayli ilginç olmuş… Burada sürelere bakmak kafa karıştırıcı bir yöntem olmuş. Neden dersen?
Senin algoritmanı ben listeden kaldırmak yerine (çünkü maliyetli bir işlem listeden çıkarmak) onun terine bir bool değişken daha tutup ona göre yapardım başkası o da güzel değil derdi başka bir şey önerirdi.. redis gibi mesela vs vs….
ÖZET: Burada kriter süre değil kaç deneme de şifreye ulaştıkları olmalıydı! ona göre algoritmayı güçlendirme yapılabilirdi! Birisi 10.000 denemede ulaşırken diğeri yavaş ama 5000denemede ulaşıyorsa ya donanım gücünü artırırsın ya da algoritmayı iyileştirir süreyi kısaltmaya çalışırsın
makale için teşekkürler
Selamlar,
Öncelikle teşekkürler:)
Makalenin tek amacı var, okuyana fikir vermek. Düşündürmek. Bunu da gördüğüm kadarı ile başarmış :)
İyi çalışmalar.
10000000…11111111…22222222….33333333……44444444……55555555…..66666666……77777777……8888888……99999999 ve son tabi bumların araları dolu olacAK KODMATİK ELLE URAŞTIM YAPMAYI DENEDİM AMA BELLİ BİR YERE KADAR DENEYE BİLDİM PARMAM ARIYOR KOD YAZARKEN
Bu şifreyi bulmak çok zor