10 Şubat 2019 Pazar

.NET Framework

        .NET Framework, yazılımcıların uygulama geliştirirken kullanabileceği derleyicileri ve birçok sınıf, metot gibi yapıyı içinde barındıran bir platformdur. Windows uygulamaları ile Windows işletim sistemi arasında bir nevi katman görevi görür. Microsoft, işletim sistemlerinin geliştirilmesinde de kullandığı bu yapıyı, esas olarak farklı geliştirme ortamları ve bu ortamlar için ayrı işler yapılmasının önüne geçmek için geliştirmiştir. Bu sayede yazılımcılar ister masaüstü, ister mobil, ister web uygulaması geliştirsin; .NET Framework ile geliştirme yapıyorsa, aynı metotlarla ve sınıflarla karşılaşır ve uygulamaları tüm bu ortamlar için çok benzer bir biçimde geliştirebilir.

        .NET Framework ile geliştirilen uygulamalara Managed Applications (Yönetilebilr Uygulamalar) denilir. Bu çatı kullanılmadan geliştirilmiş olan uygulamalar ise Unmanaged Applications (Yönetilemeyen Uygulamalar) olarak adlandırılır. Yönetilemeyen uygulamaların, geliştirici açısından en büyük dezavantajı, bellek yönetimi işleminin elle yapılması gerektiğidir. Yönetilebilir uygulamalarda ise bu işlem, .NET tarafından Garbage Collector gibi mekanizmalar ile yürütülerek, otomatik olarak gerçekleştilir.

        Bugün her ne kadar Visual Studio ya da .NET Framework denildiğinde akla ilk olarak C# programlama dili gelse de C++, J#, F# ve VB.NET gibi farklı programlama dilleri kullanarak da .NET uygulamaları geliştirilebilir. Ancak; resmi bir ifade olmasa da Microsoft, .NET Framework ile uygulama geliştirmek isteyenleri C# programlama diline yönlendirmektedir.

       
.NET Framework'te iki önemli ana öğe bulunur. Bunlar CLR ve .NET kütüphanesidir. CLR (Common Language Runtime) ortak çalışma  zamanı, geliştirilen programların çalışmasını yönetir. .NET sınıf kütüphanesiyse birçok işlevi içinde bulunduran ve sınıf sistemine göre kategorize edilmiş bir kütüphanedir. C# sürümü ile .NET Framework sürümleri farklılık gösterir. Mevcut güncel sürümler C# 6.0 ve .NET Framework 4.5'tir ve Visual Studio 2015 ile birlikte öntanımlı olarak bu sürümler kullanılmaktadır.

C# Dilinin Tarihçesi

        C# programlama dili, Microsoft tarafından ECMA ve ISO standartlarında geliştirilmiş orta seviye bir programlama dilidir. ECMA ve ISO yazılım dünyasında diller konusunda standartları belirleyen en yetkin iki kuruluştur. Microsoft, her ne kadar ilk başlarda bu standartlar çerçevesinde geliştirmeye başlasa da C# 3.0 ile birlikte kendi standardını oluşturmuş ve dili tamamen .NET için geliştirmeye başlamıştır. Dolayısıyla herhangi bir kurum ya da kuruluşa bağlı kalmaksızın, yazılım geliştiricilerin ihtiyaçlarını karşılamak için oldukça kullanışlı, güçlü ve strong typing (strongly typed) programlama dili geliştirilmiştir.
Adının temeli C ve C++ dilinden gelir. C dilinde bir tamsayı değişkenin değerini artırmak için “++” operatörü kullanılır. Bu yüzden C dilinden sonra geliştirilen ve Nesne Yönelimli (Object Oriented) özellikleri taşıyan yeni dil için, C'nin bir fazlası anlamında C++ adı kullanılmıştır. C++'tan sonra geliştirilen C# dili ise adını; ((C++)++) ifadesinde artı işaretlerinin bir araya gelmesinden alır.

        Bu dili tasarlayan ekibin başında Anders Hejlsberg bulunur ve C# dilinin geliştirilmesi ona atfedilir. Daha önce Pascal ve Delphi derleyicileri de tasarlamış olan Anders Hejlsberg; yeni geliştirdiği dilde, o dönemin en yaygın ve en beğenilen Nesne Yönelimli dili olan Java'nın söz dizimini temel almıştır.
Bir programlama dili için orta seviye ifadesinin kullanılması, o dilin gücünden kaynaklanmaz. Yazılım dünyasında diller, makine diline ya da günlük konuşma diline yakın olmalarına bağlı olarak düşük, orta ve yüksek seviye diller olarak ifade edilir. Yüksek seviye diller günlük konuşma kalıplarına benzer söz dizimlerine sahiptir. C# hem makine diline, hem de günlük konuşma diline eşit seviyede yer verir ve bundan ötürü orta seviye bir dil olarak nitelenir. C# ile sadece .NET Framework üzerinde değil, DotGNU Portable.Net ve MONO gibi çatılar ile de yazılım geliştirilebilir.
C# dilinin tasarımındaki başlıca hedefler şunlardır:
  • Basit, modern, her tür kullanım amacına uygun ve nesne yönelimli bir dil olması,
  • Güçlü tipleme kontrolü, dizin sınırları kontrolü ve tanımlanmış değişkenlerin kullanım tespiti gibi özellikler barındırması,
  • Programcı portatifliğine sahip olması,
  • Sunucu ve gömülü sistemler için tasarlanmış olması,
  • C, C++ ve Java dilini kullananların rahatlıkla alışabilecekleri şekilde tasarlanmış olması.

Dildeki Gelişmeler

C#'ıın ilk sürümü olan 1.0 ile birlikte Managed Code özelliği gelmiştir. Henüz oldukça yeni olduğu bu dönemde C#, Java ve C++'dan aldığı pek çok özellik ile birçok yazılım geliştiricisinin ilgisini çekmiştir.
C# programlama dili 2.0 sürümünde şu değişiklikler yer alır:
  • Generics
  • Partial class
  • Anonim metotlar
  • Iterator'lar (Yineleyiciler)
  • Nullable tipler
  • Delegate yapısı
Bir sonraki büyük sürüm C# 3.0'dır. En kapsamlı dil genişlemesinin bu sürümde yaşandığı söylenebilir. C# 3.0 sürümünün içerdiği başlıca yeni özellikler şunlardır:
  • LINQ (Language Integrated Query - Dil Destekli Sorgulama)
  • Lambda expressions
  • Extension metotlar
  • Expression tree
  • Implicit tipler
  • Anonim tipler
C#'ın 4.0 sürümüyle birlikte gelen özellikler ise şu şekildedir:
  • Dynamic yapılar
  • İsimlendirilebilir ve opsiyonel hale gelebilir parametreler
  • Generic co ve contra variance
C# 5.0 ile birlikte çok büyük bir değişiklik olmamıştır:
  • Asenkron özellikler
  • Caller information
C#'ın şu mevcut son sürümü olan C# 6.0 ile oldukça önemli gelişmeler gelmektedir:
  • Hizmet olarak derleyici (Rosylyn)
  • Statik tip elemanların namespace'lere import edilmesi
  • Exception filtreleri
  • Catch/finally bloklarında bekleme
  • Otomatik özellik ilklendirme
  • Getter-only özellikler için öntanımlı değerler
  • Null üretici
  • String enterpolasyonu
  • Nameof operatörü
  • Sözlük ilklendirici
Sürekli geliştirilmekte olan C# dilinin her yeni sürümüyle birlikte, o günün ihtiyaçlarının karşılanması ve programcılar için daha rahat bir geliştirme ortamının sağlanması hedeflenmektedir.
C# dilinin sürümleri ile .NET Framework sürümleri benzeşse de aralarında önemli farklılıklar vardır ve bunların birbirleriyle karıştırılmaması gerekir.

25 Aralık 2018 Salı

Algoritmalarda Karmaşıklık Hesabı


İyi Algoritma Ne Demektir?
█ Etkinlik
█ Çalışma Zamanı
█ Bellek Kullanımı
Algoritmaları karşılaştırırken daha çok çalışma zamanı ölçütü kullanılacaktır. İstenen ise çalışma zamanını giriş boyutuna bağlı olarak belirleyen bir yöntem bulmak.
                 
• Neden algoritmayı analiz ederiz?
– Algoritmanın performansını ölçmek için
– Farklı algoritmalarla karşılaştırmak için
– Daha iyisi mümkün mü? Olabileceklerin en iyisi mi?
• Özelliklerinin analizi
– Algoritmanın çalışma zamanı
– Hafızada kapladığı alan


Çalışma Zamanı Analizi (Big-O, Order of Magnitude)


Büyük-O nasıl hesaplanır?









İkili ağaçlar nedir, ikili arama ağaçları nedir, bu ağaçlarda dolaşma algoritmaları hangileridir, hangisi sıralı çıkış verir?



Bilgisayar bilimlerinde yer alan önemli veri yapılarından bir tanesi de ağaçlardır. Ağaç yapılarını önemli yapan özellikler:
·         Esneklik: Tek bir amaç için en iyi çözüm ağaç yapısı olmasa da, çoklu çözümler için ağaç yapısının esnekliği bu yapının avantajı olarak sayılabilir.
·         Etkili Arama: Arama sırasında ağacın bazı dalları budanarak arama yapılması performans artışı sağlar ve bu da verimliliği arttırır. Ağaç yapısı genellikle bilginin istenilen bölümüne konumlanmak için genellikle filtreleme aracı olarak kullanılır.
·         Doğal Temsil: Bilgiyi temsil etmenin doğal bir yoludur.
·         Ağaç yapısı bir uygulamayı bazen daha kolay uygulanabilir bir hale dönüştürür.

Bağlı listeler, yığıtlar ve kuyruklar doğrusal (linear) veri yapılarıdır. Ağaçlar ise doğrusal olmayan belirli niteliklere sahip iki boyutlu veri yapılarıdır (Şekil 1). Ağaçlardaki düğümlerden iki veya daha fazla bağ çıkabilir. İkili ağaçlar (binary trees), düğümlerinde en fazla iki bağ içeren (0,1 veya 2) ağaçlardır. Ağacın en üstteki düğümüne kök (root) adı verilir.

 



Şekil 1 : Bir ikili ağacın grafiksel gösterimleri

Şekil 1'de görülen ağacın düğümlerindeki bilgiler sayılardan oluşmuştur. Her düğümdeki sol ve sağ bağlar yardımı ile diğer düğümlere ulaşılır. Sol (leftptr) ve sağ (rightptr) bağlar boş ("NULL" = "/" = "\") da olabilir. Düğüm yapıları değişik türlerde bilgiler içeren veya birden fazla bilgi içeren ağaçlar da olabilir. Doğadaki ağaçlar köklerinden gelişip göğe doğru yükselirken veri yapılarındaki ağaçlar kökü yukarıda yaprakları aşağıda olacak şekilde çizilirler.
Şekil 2'deki ağaç, A düğümü kök olmak üzere 9 düğümden oluşmaktadır. Sol alt ağaç B kökü ile başlamakta ve sağ alt ağaç da C kökü ile başlamaktadır. A'dan solda B'ye giden ve sağda C'ye giden iki dal (branch) çıkmaktadır.

 



Şekil 2 : Ağaçlarda düzeyler

 Tanımlar (Örnekler Şekil 2'ye göre verilmiştir) :
1)      İkili Ağaç (Binary Tree) : Sonlu düğümler kümesidir. Bu küme boş bir küme olabilir (empty tree). Boş değilse şu kurallara uyar.
i) Kök olarak adlandırılan özel bir düğüm vardır.
ii)                 Her düğüm en fazla iki düğüme bağlıdır.
iii)               Kök hariç her düğüm bir daldan gelmektedir.
iv)               Tüm düğümlerden yukarı doğru çıkıldıkça sonuçta köke ulaşılır.
2)      Düğüm (node) : Ağacın her bir elemanına düğüm adı verilir. Örnekler : A, B, C.
3)      Kök (root) : Düzey 0'daki (şemanın en üstündeki) tek düğüm. Örnek : Şekil 2'de A bilgisini içeren düğüm.
4)      Çocuk (child) : Bir düğümün sol ve sağ bağı aracılığı ile bağlandığı düğümler o düğümün çocuklarıdır. Örnek : B ve C, A'nın çocuklarıdır.
5)      Parent : Bir düğüm, sağ ve sol bağları ile bağlandığı düğümlerin parent'ıdır. A düğümü, B ve C düğümlerinin parent'ıdır.    
6)      Bir düğümün düzey (level) veya derinliği (depth) : Bir düğümün kök düğümden olan uzaklığıdır. Örnek : D düğümünün düzeyi veya derinliği 2'dir.
7)      Ağacın derinliği (depth of tree) : En derindeki yaprağın derinliği veya yüksekliği (height). Örnek : Şekil 2'deki ağacın derinliği 3'tür.
8)      Yaprak (leaf) : Sol ve sağ bağı boş olan düğümlere yaprak adı verilir. Örnekler : D,G,H,I.
9)      Kardeş (sibling, brother) : Aynı parent'a sahip iki düğüme kardeş düğümler adı verilir. Örnekler : B ile C kardeştir. D ile E kardeştir. H ile I kardeştir.
10)  Ancestor (üst düğüm) : Bir düğümün parent'ı birinci ancestor'ıdır. Parent'ın parent'ı (recursion) ikinci ancestor'ıdır. Kök, kendi hariç tüm düğümlerin ancestor'ıdır.
11)  Descendant (alt düğüm) : Bir düğümün iki çocuğu birinci descendant'larıdır. Onların çocukları da ikinci descendant'larıdır.   
12)  Full binary tree : i) Her yaprağı aynı derinlikte olan ii) Yaprak olmayan düğümlerin tümünün iki çocuğu olan ağaç Full (Strictly) Binary Tree'dir (İkinci şart yeterli). Bir full binary tree'de n tane yaprak varsa bu ağaçta toplam 2n-1 düğüm vardır.
13)  Complete binary tree : Full binary tree'de yeni bir derinliğe soldan sağa doğru düğümler eklendiğinde oluşan ağaçlara Complete Binary Tree denilir. Böyle bir ağaçta bazı yapraklar diğerlerinden daha derindir. Bu nedenle full binary tree olmayabilirler. En derin düzeyde düğümler olabildiğince soldadır. 
14)  General Tree (Ağaç) : Her düğümün en fazla iki çocuğu olabilme sınırı olmayan ağaçlardır.
15)  İkili Arama Ağacı (Binary Search Tree) : Boş olan veya her düğümü aşağıdaki şartlara uyan anahtara sahip bir ikili ağaçtır :
i)                    Kökün solundaki alt ağaçlardaki (eğer varsa) tüm anahtarlar kökteki anahtardan küçüktür.
ii)                  Kökün sağındaki alt ağaçlardaki (eğer varsa) tüm anahtarlar kökteki anahtardan büyüktür.
iii)                Sol ve sağ alt ağaçlar da ikili arama ağaçlarıdır.


İkili Ağaçlar ve İkili Ağaçlar Üzerindeki Dolaşma İşlemleri
Dolaşma (traverse), ağaç üzerindeki tüm düğümlere uğrayarak gerçekleştirilir. Ağaçlar üzerindeki dolaşma işlemleri, ağaçtaki tüm bilgilerin listelenmesi veya başka amaçlarla yapılır. Doğrusal veri yapılarında baştan sona doğru dolaşmak kolaydır. Ağaçlar ise düğümleri doğrusal olmayan veri yapılarıdır. Bu nedenle farklı algoritmalar uygulanır. Çok bilinen yöntemler üç tane olup özyinelemeden yararlanırlar :
1)      Preorder (depth-first order) Dolaşma (Traversal)
i)                    Köke uğra (visit)
ii)                  Sol alt ağacı preorder olarak dolaş.
iii)                Sağ alt ağacı preorder olarak dolaş.
2)      Inorder (Symmetric order) Dolaşma
i)                    Sol alt ağacı inorder'a göre dolaş
ii)                  Köke uğra (visit)
iii)                Sağ alt ağacı inorder'a göre dolaş.
3)      Postorder Dolaşma
i)                    Sol alt ağacı postorder'a göre dolaş
ii)                  Sağ alt ağacı postorder'a göre dolaş.
iii)                Köke uğra (visit)


Şekil 3 : İkili Ağaç ve değişik şekillerde dolaşılması
İkili Arama Ağaçları
İkili arama ağaçları, her bir düğümün solundaki (sol alt ağacındaki) tüm düğümler kendisinden küçük, sağındakiler (sağ alt ağacındakiler) de kendisinden büyük olacak şekilde oluşturulurlar (Şekil 4). İkili arama ağaçlarındaki en önemli işlemlerden birisi aramadır.
Örnek olarak aşağıdaki ağaçta, 44 sayısını aratmak için şu işlem sırası izlenir :
Karşılaştırma 1            : 44, 47 ile karşılaştırılır. 44<47 olduğundan sol bağdan ilerlenir.
Karşılaştırma 2            : 44, 25 ile karşılaştırılır. 44>25 olduğundan sağ bağdan ilerlenir.
Karşılaştırma 3            : 44, 43 ile karşılaştırılır. 44>43 olduğundan sağ bağdan ilerlenir.
Karşılaştırma 4            : 44 == 44. Aranan anahtar değeri ağaçta bulundu!

Örnek olarak aşağıdaki ağaçta, 90 sayısını aratmak için şu işlem sırası izlenir :
Karşılaştırma 1            : 90, 47 ile karşılaştırılır. 90>47 olduğundan sağ bağdan ilerlenir.
Karşılaştırma 2            : 90, 77 ile karşılaştırılır. 90>77 olduğundan sağ bağdan ilerlenir.
Karşılaştırma 3            : 90, 93 ile karşılaştırılır. 90<93 olduğundan sol bağdan ilerlenir.
            : NULL. Aranan anahtar değeri ağaçta bulunamadı.


Şekil 4 : İkili Arama Ağacı
Görüldüğü gibi arama işleminin etkinliği ağacın yüksekliğine bağlıdır. İkili arama ağaçları dengeli tutulabilirse, bir anahtar değerini aramada oldukça hızlıdırlar. Böyle olduğunda n elemanlı bir ağaç en fazla log2n düzeyden oluşur. Bir değerin bulunması veya ağaçta olmadığının belirlenmesi için en fazla log2n karşılaştırma yapılır. Örnek olarak 1000 elemanlı bir ikili arama ağacında bir elemanın bulunabilmesi için en fazla 10 karşılaştırma yapmak gerekecektir (210=1024 > 1000). Bağlı listelerde ise bulunacak elemanın değerine göre (eleman sonda ise) 1000 karşılaştırma yapmak gerekebilir. 
Düğüm sayısı n olan Complete Binary Tree'de derinliği hesaplayabiliriz.
n = 20 + 21 + 22 +... + 2d = 2d+1-1 => n+1 = 2d+1 => d = log2(n+1) - 1'dir.
15 düğümlü bir ağaçta d = log2(15+1) - 1 = 4-1 = 3'tür.
İkili ağaçlardaki dolaşma işlemlerinin tümü ikili arama ağaçlarında da kullanılır. İkili arama ağaçları üzerinde inorder dolaşıldığında tüm elemanlar küçükten büyüğe sıralı bir şekilde karşımıza gelecektir.
İkili arama ağaçları, tekrarları önlemek açısından da oldukça yararlıdırlar. Ağaç oluşturulurken tekrar eden bir eleman eklenmek istendiğinde, kökten itibaren sola git, sağa git kararları ile o değerin olduğu yere hızlıca ulaşılacak ve ağaçta (veriler içinde) o değerin zaten olduğu anlaşılacaktır. Bu şekilde tekrar eden verilerin olması engellenir.  
Bunlar dışında ikili arama ağacından düğüm silme, ikili arama ağacını iki boyutlu ağaç biçiminde ekrana çizdirme, ağacı düzey sırasında dolaşma (düzey düzey soldan sağa) gibi algoritmalar da yazılabilir. Ayrıca ağaç düzeyini bulma, ağaca string de dahil birçok bilgi ekleme gibi işlemler de yapılabilir.
Bağlı liste veri yapısında ekleme, silme ve arama  işlemleri listedeki eleman sayısı n olmak üzere O(n)  kadar zaman almaktadır. İkili ağaç veri yapısı ise h  ağacın derinliğini göstermek üzere bu işlemlerin O(h)  kadar zamanda yapılmasını sağlar.  Dengeli bir ikili ağaçta sağ ve sol alt ağaçların derinlikleri farkı en fazla birdir. Eğer elimizdeki n tane elemanı dengeli bir ikili ağaca yerleştirirsek, bu ağaçtaki elemanlara ulaşma, ekleme ve silme işlemleri O(log n) kadar zaman alır.