Bana kod yazmayı öğret baba – Bölüm 6
“Algoritma fikirse, programlama dili kalem-kâğıt. Kalemle yazmayı öğrenmek önemli ama daha önemlisi kafadaki öyküyü (algoritmayı) kurgulamak.” Hafız Lakyab, Haziran 2017
Akşamüstü TV karşısında pinekliyorsunuz. Hafiften mideniz kazınmaya başladı. Ne yapabilirsiniz? Önünüzde birkaç seçenek var. Dolapta yemeklik malzeme varsa ve yemek yapmayı becerebiliyorsanız pişirebilirsiniz. Bir arkadaşınızı kafalayabilirseniz beraber dışarı çıkıp yemek yiyebilirsiniz. Ya da telefona uzanıp bir yerden yemek sipariş edebilirsiniz. Bu durumda beyniniz nasıl karar veriyor, bir düşünelim:
- eğer yemek yapmayı biliyorum ve evde yemeklik malzeme var -> Pişir.
- yoksa eğer yemeğe çıkacak bir arkadaş buldum -> Dışarıda ye.
- yoksa -> Sipariş ver.
Beynimizin ne yaptığını biraz teknik terimlerle açıklayalım.
- Karnımızın acıkması: problem
- Problemi çözmek için beynimizin kurduğu kurallar silsilesi: algoritma
Algoritma deyince pek çoğumuzun aklına robotlar, bilgisayar programları, filmlerdeki gibi klavyesine bakmadan saniyede otuz tuş basarak kod yazan hackerlar falan gelebilir. Bunlar tabii ki en çılgın algoritmaların yazıcıları ve uygulayıcıları fakat beynimizi ve her gün çözdüğümüz problemleri de yabana atmamak lazım. Mesela, pek çok kullandığımız bir problem ve algoritmaya göz atalım.
Problem: Bir sayının tek veya çift olduğunu tespit etmek.
Algoritma: Son hanesi 1, 3, 5, 7 veya 9’sa tektir. Yoksa çift.
Bir problemin tek bir algoritması mı vardır? Hayır. Mesela yukarıdaki problem için yeni bir algoritma geliştirdim ben. Bakın bakalım beğenecek misiniz:
Algoritma 2: Sayıyı al, eldeki sayı 2’den küçük kalana kadar kendisinden devamlı 2 çıkar. Kalan sayı 1’se sayımız tek, 0’sa çifttir.
Başka bir deyişle, sayıdan devamlı 2 çıkartıp eninde sonunda sayının 2’yle bölümünden kalanını buluyorum. İşte saçmalık benimkisi de, niye o kadar uğraşıyorsam..?
Homo sapiens olarak bilmem kaç bin yıllık hükümdarlığımız süresince devamlı problemlerle karşılaştık ve problemleri çözmek için algoritmalar geliştirdik. En başta avlanmak için, sonra mevsim zamanlarını tespit etmek için, sonra mancınıkları doğru açılarda fırlatmak için, sonra köprü kurmak için, sonra da Ay’a araç göndermek için. O vakte kadar geliştirdiğimiz algoritmaların hepsini kâğıdı kalemi elimize alarak kendimiz çözdük. Fakat son zamanlarda problemler gitgide büyüdü. Kâğıda kaleme sığmaz oldu. Ama biz de büyüdük. Önce bilgisayarları, sonra programlama dillerini geliştirdik. Artık sadece algoritmaları yazıp uygulamasını bilgisayarlara yaptırabilirdik. Peki nasıl? Programlama dillerini kullanarak.
Varsayalım ki yukarıdaki, benim yazmış olduğum tuhaf algoritmayı bilgisayarımızda uygulamak istiyoruz. Bunun için yapmamız gereken ilk şey algoritmayı biraz daha adım adım kurallar çerçevesine sokup bir bilgisayarın anlayacağı şekle sokmak. Yani:
Pseudo-code:
- Adım 1: Elindeki sayıyı al, 2 çıkar. Adım 2’ye git.
- Adım 2: Yeni bulduğun sayı 2’den küçük mü? Evetse Adım 3’e git. Yoksa Adım 1’e dön.
- Adım 3: Dur. Son bulduğun sayı 1’se tek, 0’sa sayımız çift.
Bu yazdığımız şey, dikkat ederseniz, ilk yazdığımıza göre daha organize ve insanın biraz daha anlayacağı bir dilden. Ama hâlâ kopyalanıp Python’a yapıştırılacak halde değil. Biz buna İngilizce’de pseudo-code (südokod şeklinde okunuyor) diyoruz. Türkçe’de ne diyoruz, açıkçası bilmiyorum. Bir ilginç ayrıntı da şu, adımlarda geriye gidebiliyoruz. Hatırlarsanız Python’da kod yazarken devamlı yukarıdan aşağı doğru akıyorduk. Merak etmeyin, yakında bu kuralı da değiştireceğiz.
Pseudo-code elinize geçince ilk yapacağınız şey onu test etmek olmalı. Mesela yukarıdakini 5 sayısıyla test edelim.
- Adım 1: 5’ten 2 çıkardım 3 kaldı. Adım 2’ye gidiyorum.
- Adım 2: Bulduğumuz 2’den küçük değil. Adım 1’e gidiyorum.
- Adım 1: 3’ten 2 çıkardım 1 kaldı. Adım 2’ye gidiyorum.
- Adım 2: Bulduğumuz sayı 2’den küçük. Adım 3’e gidiyorum.
- Adım 3: Bulduğum sayı 1. Cevap tek.
Pseudo-code’lar, bir önceki derste çözdüğümüz “şampiyon kim olacak?” veya “sayı tek mi çift mi?” kadar basit problemler için şart değil. Hatta zaman kaybı. Ama ileride karşılaşacağımız karmaşık problemler için olmazsa olmaz şeyler. O yüzden sevgili geleceğin koderları, beşinci kuralımızı lütfen aklınızın bir köşesine yazınız.
Beşinci kural: Kod yazarken sırasıyla yapmanız gereken şeyler:
- Kodlamanız gereken probleme iyice kafa yorun ve onu çözecek bir algoritma geliştirin.
- Algoritmanın pseudo-code’unu yazın. Evet, kâğıt kalem alın, yazın.
- Alın bu pseudo-code’u bildiğiniz programlama dillerinden birinde yazın ve kodunuzu çalıştırın.
Yazının başındaki algoritma-öykü analojisinin ne demek olduğunu şimdi daha iyi anlayabiliriz. Daktilo, kâğıt kalem veya Microsoft Word kullanmayı çok iyi beceriyor olabilirsiniz ama kafanızda bir öykü kurgulanmamışsa bir yazar olamazsınız. Programlamada da aynı mantık geçerli. Python, C, Fortran veya R syntax’ini, fonksiyonlarını çok iyi biliyor olabilirsiniz ama probleminiz için bir algoritma geliştiremezseniz o problemi çözmenize imkân yoktur. Algoritma, problemi çözmek için bir fikirdir. Programlama dilleri ise bunun uygulanması için birer araçtır. Öykünüzü/algoritmanızı kurguladıktan sonra hangi aracı/programlama dilini seçeceğiniz size kalmış. İster daktilo kullanın, ister Word. İster Python kullanın, ister C++. O yüzden çevrenizden çokça duyarsınız:
Programlama dillerinin hepsi aynı abi ya. Birini öğrenince diğerlerinde de yazabiliyosun.
Aslında coderımız burada şunu söylemek istiyor:
Algoritma geliştirdikten sonra tüm programlama dillerinde uygulayabiliyorsun.
If’tir else’tir kaptırmış gidiyorken bu kadar algoritma goygoyunu neden yaptık? Çünkü bir sonraki konumuz while’lar, for’lar, loop’lar olacak ve kodlayacağımız problemlerin karmaşıklığını bir iki gömlek yukarı çekeceğiz. O yüzden olaya balıklama dalmadan bu işin kökenine bir inelim dedik.
Ne diyorduk? Karmaşık problemler için birer algoritma şart ve algoritmanın pseudo-code’unu yazmak çoğu zaman faydalı. O yüzden bir sonraki konumuza geçmeden birkaç problem ele alalım, algoritmalar ve pseudo-codelar yazalım.
Problem: Şampiyonun kim olacağını tespit etmek.
Algoritma: Takımların puanlarını hesapla. En yüksek puanlı tek bir takım varsa o şampiyon. Değilse, en yüksek puanlı takımların averajına bak. O averaj tek bir takıma aitse o şampiyon. Değilse…
Problem: Verilen bir cümlenin kaç kelime olduğunu hesaplamak.
Algoritma: Cümle içindeki boşlukları (” “) say. Sonra bulduğun sayıyı bir artır.
Problem: Verilen dört sayının ortalamasını hesaplamak.
Algoritma: Sayıların hepsini topla ve bulduğun sayıyı dörde bol.
Buraya kadar gayet basit algoritmalar yazdık. Şimdi seviyeyi biraz yükseltelim.
Problem: Verilen bir sayının 1000’den küçük en büyük tam sayı katını bulmak. Sayının 1000’den küçük olduğunu varsayalım.
Yıllarca alınan matematik dersleri sağ olsun, böyle bir problem verildiği anda kafadan bazı kurallar uygulayıp çözmeye başlıyoruz. Mesela “53’ü 10’la çarp” dediklerinde hiç düşünmeden 53’ün sonuna 0 ekliyoruz. Problemler biraz zorlaşınca ise biraz kafa yormamız gerekiyor. Böylesi bir problem ilk defa elinize geçtiğinde muhtemelen şöyle düşünüyorsunuz:
– Bir kere 500’den büyükse 1000’den küçük en büyük katı kendisi olacak. Çünkü 500’den büyük sayıyı 2’yle çarpınca 1000’den büyük oluyor.
– Evet doğru. Peki ya 500’den küçükse?
– O zaman dur bir hesaplayım. Şimdi 500’den küçükse 2 katı olacak ama nereye kadar? 1000’i 3’e bölersem 333.33 çıkar. Yani 333’le 500 arasındaysa o sayının 2 katı olacak. Eğer 333’ten de küçükse… Ohoooo abi bu böyle gider. Şimdi nasıl yapacağız bunu?
Aslında gayet doğru yoldasınız. Fakat bu problemi çözecek algoritmayı geliştirmek için biraz fikirlerinizi toparlayıp düzgün bir şekilde kâğıda dökmeniz gerekiyor. Ayrıca unutmayın, bu çözümü eninde sonunda bir bilgisayara anlatacağız. Biraz da onun anlayacağı dilden yazmamız gerekiyor.
Peki o zaman, şöyle bir çözüm geliştirelim. Verilen sayıyı alalım. Teker teker 1’le, 2’yle, 3’le, birer birer artırarak çarpalım. Çarpım 1000’i geçerse duralım ve en son çarpım değerini cevap olarak kaydedelim.
Algoritma: Verilen sayıyı kenara not et. Şimdi onu 2’yle çarp. Elde ettiğin sayı 1000’den büyükse dur. Yoksa elde ettiğin sayıyı kenara not et. Şimdi verilen sayıyı 3’le çarp. Elde ettiğin sayı 1000’den büyükse dur. Yoksa elde ettiğin sayıyı kenara not et. Bu şekilde çarptığın sayıyı birer artırarak devam et. Cevap kenara not ettiğin sayı olacak.
Dikkat ederseniz algoritma dahilinde üç farklı sayı biriminden bahsediyoruz: 1. Başta bize verilen sayı, 2. Bize verilen sayıyı çarptığımız iki, üç diye artarak giden çarpma sayısı, 3. Çarpma işlemi sonucunda elde ettiğimiz sayı. Yani işler biraz karışıyor. Konuyu biraz daha berraklaştırmak için bir pseudo-code yazalım ve orada bu sayı birimlerini aynen Python’da kod yazar gibi tanımlayalım.
Pseudo-code:
- Adım 1: Verilen sayıyı kaydet. Çarpım sayısını 1’e eşitle.
- Adım 2: Çarpım sayısını 1 artır.
- Adım 3: Verilen sayıyı çarpım sayısıyla çarp. Sonucu kaydet. Sonuç 1000’den büyükse Adım 4’e git. Değilse Adım 2’ye git.
- Adım 4: Cevap en son kaydettiğin sayı.
Şimdi adım adım pseudo-code’u uygulayalım. Verilen sayı 220 olsun.
- Adım 1: verilen sayı = 220, çarpım sayısı = 1. Adım 2’ye gidiyoruz.
- Adım 2: çarpım sayısı = 2 oldu. Adım 3’e gidiyoruz.
- Adım 3: verilen sayı çarpım sayısıyla çarpıldı sonuç 440 olarak kaydedildi. Sonuç 1000’den büyük değil. O yüzden Adım 2’ye gidiyoruz.
- Adım 2: çarpım sayısı = 3 oldu. Adım 3’e gidiyoruz.
- Adım 3: verilen sayı çarpım sayısıyla çarpıldı sonuç 660 olarak kaydedildi. Sonuç 1000’den büyük değil. O yüzden Adım 2’ye gidiyoruz.
- Adım 2: çarpım sayısı = 4 oldu. Adım 3’e gidiyoruz.
- Adım 3: verilen sayı çarpım sayısıyla çarpıldı sonuç 880 olarak kaydedildi. Sonuç 1000’den büyük değil. O yüzden Adım 2’ye gidiyoruz.
- Adım 2: çarpım sayısı = 5 oldu. Adım 3’e gidiyoruz.
- Adım 3: verilen sayı çarpım sayısıyla çarpıldı sonuç 1100 olarak kaydedildi. Sonuç 1000’den büyük. O yüzden Adım 4’e gidiyoruz.
- Adım 4: Cevap son kaydettiğimiz sayı, yani 1100.
Hata yapmak bu işin doğasında var dostlar ama bu benim gayet bilinçli bir hatam oldu (evet klasik hoca tribi). Çünkü güzel bir ödev sorusuna ihtiyacım vardı.
Ödev 6.1: Yukarıdaki pseudo-code’u düzelterek algoritmanın doğru cevap olan 880’i bulmasını sağlayın. İpucu: hata üçüncü adımda.
Bu arada algoritma geliştirirken en önemli noktalardan birini yeni kuralımız olarak da eklemeyi ihmal etmeyelim.
Altıncı kural: Algoritmalar tek bir girdiye özel değil tüm girdiler için doğru çalışabilecek olmalıdır.
Mesela bir önceki ödevde geliştireceğemiz algoritma sadece 220 girdisiyle değil, tüm tam sayı girdileriyle doğru sonucu bulabilecek olmalıdır. 3, 100, 999 farketmez. Bu bölümü kapatmadan önce algoritma yazımıyla alakalı ne gibi şeyler öğrendik bir özetleyelim ve önemli kısımları vurgulayalım.
Öncelikle, her algoritmanın içinde “çarpım sayısı, leylanın saç rengi” gibi değişkenler vardır, olacaklardır. Onları algoritmanın içindeki önemli noktaların değerlerini tutmaları için kullanacağız. Nasıl kalem kağıtla bir problem çözerken soyut bazı değerlere x, y, z gibi isimler verip onların değerlerini bu değişkenlerin içine saklayarak problemi çözüyoruz, burada da aynı şeyi yapacağız. Daha doğrusu Python’a yaptıracağız. O yüzden bu tür değişkenler tanımlarken ismen mantıklı bir şeyler kullanın. Abuk_subuk, yalan_dolan gibi tuhaf değişken isimlerinden kaçınınız.
Algoritma yazımına tecrübeli değilseniz bodoslama girmeyin. Bu problemi size sorduklarında kafanızda soruyu nasıl çözmeye başlıyorsunuz? Bunu düşünerek önce değişkenlerinizi belirleyin, sonra adımlarınızı teker teker yazın. En son olarak algoritmanızı farklı değerlerle test edin. Hatalarınızı buldukça adımlarınızı, değişkenlerinizi düzeltin. Çoğu zaman ilk yazdığınız algoritmaya yeni değişkenler eklemeniz gerekeceğini göreceksiniz.
Aynı problemi çözen birden fazla algoritma olabilir. Bir algoritmanın diğerine göre daha az adımda sonucu bulması diğer algoritmayı hatalı kılmaz. Yazdığınız algoritmanın sonucu hızlı buluyor olması tabii ki önemlidir ama bu daha çok profosyonel yazılımcıların bir sorunu. Bu ders çerçevesinde tek umurunuzda olan şey doğru algoritmayı yazmak olmalı.
Yukarıdaki kuralları göz önüne alarak son bir pseudo-code örneği daha örneği verelim. Hedefimiz bu: “Size iki tane tam sayı verilsin: x ve y. x’in y’ye bölümünden kalanını hesaplayan bir algoritmanın pseudo-code’nu yazın.” Burada değişkenleri nasıl kullandığımıza dikkat edin.
- Adım 1: Verilen x sayısını z’ye eşitle.
- Adım 2: z sayısı y’den küçükse dur, cevap z. Değilse Adım 3’e git.
- Adım 3: z’yi y kadar azalt. Adım 2’ye git.
O zaman yavaştan bu bölümü sonlandıralım (Tabii ki birbirinden güzel ve faydalı ödevler ve bir önceki dersin çözümleriyle).
Ödev 6.2: Size verilen bir x sayısının tam kare bir sayı olup olmadığını tespit eden bir algoritmanın pseudo-code’unu yazın.
Ödev 6.3: Verilen bir kelimenin büyük ünlü uyumuna uygun olup olmadığını bulan bir algoritmanın pseudo-code’nu yazın.
Ödev 6.4: Bir sayının asal sayı olup olmadığını bulan bir algoritmanın pseudo-code’nu yazın.
Ödev 6.5: Bilgecan Dede fizik araştırmalarından arta kalan vaktinde spor yaparak sağlığını korumak amacındadır. Her gün koşu bandına atlar, hızını 7 km/saat’e ayarlar ve her 100 metrede bir hızı 0.1 km/saat artırır. Bilgecan Dede’nin x km’yi kaç dakikada koşacağını hesaplayan bir algoritmanın pseudo-code’nu yazın. Not: bu soru gayet gerçekten sorulup tartışılmıştır.
Ödev 5.1 çözüm:
isim = input("Adiniz?") cinsiyet = input("Cinsiyetiniz? (k/e)") yas = int(input("Yasiniz?")) if yas < 18: print("Selam " + isim + "!") elif cinsiyet == "e": print("Selam " + isim + " Bey!") elif cinsiyet == "k": print("Selam " + isim + " Hanim!") else: print("Selam " + isim + "!")
Ödev 5.2 çözüm:
bjk_puan = 78 gs_puan = 77 fb_puan = 76 bjk_mac_sonucu = input("BJK maci ne oldu? (k/b/y seklinde cevap verelim lutfen)") gs_mac_sonucu = input("GS maci ne oldu? (k/b/y seklinde cevap verelim lutfen)") fb_mac_sonucu = input("FB maci ne oldu? (k/b/y seklinde cevap verelim lutfen)") if bjk_mac_sonucu == "k": bjk_puan = bjk_puan + 3 elif bjk_mac_sonucu == "b": bjk_puan = bjk_puan + 1 if gs_mac_sonucu == "k": gs_puan = gs_puan + 3 elif gs_mac_sonucu == "b": gs_puan = gs_puan + 1 if fb_mac_sonucu == "k": fb_puan = fb_puan + 3 elif fb_mac_sonucu == "b": fb_puan = fb_puan + 1 if bjk_puan > gs_puan and bjk_puan > fb_puan: print("Sampiyon BJK!") elif gs_puan > bjk_puan and gs_puan > fb_puan: print("Sampiyon GS!") elif fb_puan > bjk_puan and fb_puan > gs_puan: print("Sampiyon FB!") else: print("Sampiyon averajla belirlenir. Evet usendim simdi kodu uzatmaya.")
Ödev 5.3 çözüm:
isim = input("Adiniz?") cinsiyet = input("Cinsiyetiniz? (k/e)") yas = int(input("Yasiniz?")) if cinsiyet == "e" and yas >= 18: print("Selam " + isim + " Bey!") elif cinsiyet == "k" and yas >= 18: print("Selam " + isim + " Hanim!") else: print("Selam " + isim + "!")
Ödev 5.4 çözüm:
sayi1 = input("Birinci sayiyi alayim") sayi1 = int(sayi1) sayi2 = input("Ikinci sayiyi alayim") sayi2 = int(sayi2) sayi3 = input("Ucuncu sayiyi alayim") sayi3 = int(sayi3) if sayi1 >= sayi2 and sayi1 >= sayi3 and sayi2 >= sayi3: print("En buyuk birinci, en kucuk ucuncu sayi.") elif sayi1 >= sayi2 and sayi1 >= sayi3 and sayi3 >= sayi2: print("En buyuk birinci, en kucuk ikinci sayi.") elif sayi2 >= sayi1 and sayi2 >= sayi3 and sayi1 >= sayi3: print("En buyuk ikinci, en kucuk ucuncu sayi.") elif sayi2 >= sayi1 and sayi2 >= sayi3 and sayi3 >= sayi1: print("En buyuk ikinci, en kucuk birinci sayi.") elif sayi2 >= sayi1: print("En buyuk ucuncu, en kucuk birinci sayi.") else: print("En buyuk ucuncu, en kucuk ikinci sayi.")
Ödev 5.5 çözüm:
bjk_mac_sonucu = input("BJK maci ne oldu? (k/b/y seklinde cevap verelim lutfen)") gs_mac_sonucu = input("GS maci ne oldu? (k/b/y seklinde cevap verelim lutfen)") if bjk_mac_sonucu == "b" and gs_mac_sonucu == "k": gs_fark = input("GS kac farkla kazandi?") gs_fark = int(gs_fark) if gs_fark >= 3: print("Sampiyon GS!") else: print("Sampiyon BJK!") else: print("Sampiyon BJK!")
Ödev 5.6 çözüm:
bjk_mac_sonucu = input("BJK maci ne oldu? (k/b/y seklinde cevap verelim lutfen)") gs_mac_sonucu = input("GS maci ne oldu? (k/b/y seklinde cevap verelim lutfen)") bjk_averaj= int(input("BJK averaji nedir?")) gs_averaj = int(input("GS averaji nedir?")) if bjk_mac_sonucu == "b" and gs_mac_sonucu == "k": gs_fark = input("GS kac farkla kazandi?") gs_fark = int(gs_fark) if gs_fark + gs_averaj >= bjk_averaj: print("Sampiyon GS!") else: print("Sampiyon BJK!") else: print("Sampiyon BJK!")
Hafız Lakyab
Yazar: Hafız Lakyab (tümünü gör)
- Dev Kütleli Bir Kara Deliğin Olması Gereken Yer, Galaksisinin Merkezi midir? - 17 Eylül 2019
- Bana kod yazmayı öğret baba – Bölüm 9 - 10 Mart 2019
- Bana kod yazmayı öğret baba – Bölüm 8 - 24 Şubat 2019
- Bana kod yazmayı öğret baba – Bölüm 7 - 10 Şubat 2019
- Bana kod yazmayı öğret baba – Bölüm 6 - 27 Ocak 2019