Bir veri yapısındaki karmaşık listeler nelerdir? Türler ve veri yapıları

  • 23.06.2019

Algoritma oluşturmak için gerekli bir koşul, veri resmileştirme, yani bazılarına bilgi getirmek bilgi modeli(santimetre. " bilgi modelleri”) Zaten tanımlanmış ve araştırılmıştır. Böyle bir model bulunduğunda tanımlı olduğu söylenir. soyut veri yapısı.

Soyut veri yapısı nesnenin işaretlerini ve özelliklerini tanımlar, ara bağlantı nesnenin öğeleri arasında, mümkün olduğu kadar operasyonlar Belirli bir nesne veya nesne sınıfı üzerinde.

Bilgisayar biliminin görevlerinden biri, bilgisayar işlemeye uygun bilgi sunum biçimlerini bulmaktır. Kesin bir bilim olarak bilgisayar bilimi, resmi (matematiksel olarak titizlikle tanımlanmış) nesnelerle çalışır. Bu tür nesneler - temel soyut veri yapıları bilgisayar biliminde kullanılanlar şunlardır:

· bütün sayılar;

· Gerçek sayılar;

· Semboller;

· Boole değerleri.

Bu nesnelerin programlama dillerinde bilgisayarla işlenmesi için ilgili veri tipleri(santimetre. " Veri tipleri”). Temel nesneler, bir bütün olarak yapı üzerinde işlemler ve bu soyut veri yapısının tek tek öğelerine erişim için kurallar eklenerek daha karmaşık yapılarda birleştirilebilir.

Bu soyut veri yapıları şunları içerir:

· Vektörler (sonlu diziler);

· Tablolar (matrisler) ve genel durumda - çok boyutlu diziler;

Dinamik yapılar:

Sembol dizileri, sayılar;

Kuyruklar;

Ağaçlar;

İyi bir veri yapısı seçimi, genellikle etkili bir algoritma ve onu uygulayan bir program oluşturmanın anahtarıdır: veri yapılarının ve gerçek nesnelerin analojisini kullanarak sorunlara etkili çözümler bulabilirsiniz.

Listelenen yapıların programlamadaki uygulamalarından bağımsız olarak var olduğuna dikkat edin. Bu veri yapıları, bilgisayar makinesinin henüz icat edilmediği 18. ve 19. yüzyıllarda kullanıldı. Soyut bir veri yapısı açısından bir algoritma tasarlayabiliriz, ancak algoritmayı belirli bir programlama dilinde uygulamak için, onu aşağıdaki terimlerle temsil etmenin bir yolunu bulmamız gerekir. veri tipleri ve operatörler bu programlama dili tarafından desteklenir (bkz. Programlama dili operatörleri”). Soyut yapıların bilgisayar gösterimi için aşağıdakiler kullanılır: veri yapıları belirli bir şekilde birleştirilmiş değişkenler, muhtemelen farklı veri türleri topluluğudur. Vektör, tablo, dizi, dizi gibi yapılar oluşturmak için çoğu programlama dilinde standart vardır. veri tipleri: sırasıyla tek boyutlu dizi, iki boyutlu dizi, dize, dosya (daha az sıklıkla bir liste). İlk etapta geri kalan veri yapılarının organizasyonu dinamik yapılar Programın yürütülmesi sırasında boyutu değişen programcı, temel veri türlerini kullanarak bağımsız olarak yürütmek zorundadır. Bu tür yapıları daha ayrıntılı olarak ele alalım.

Listeler

Doğrusal liste- Listede rastgele bir yere eleman ekleme ve herhangi bir elemanı silme işlemlerine izin verilen lineer olarak bağlı elemanlar dizisi. Doğrusal bir liste, listenin başına bir işaretçi tarafından benzersiz bir şekilde tanımlanır. Listelerdeki tipik işlemler şunlardır: bir listede gezinme, belirli bir öğeyi bulma, belirli bir öğeden hemen sonra veya önce öğe ekleme, belirli bir öğeyi silme, iki listeyi bir listede birleştirme, bir listeyi iki veya daha fazla listeye bölme, vb.

Doğrusal bir listede, hariç her öğe için ilk, orada öncesi eleman; hariç her eleman için son, orada sonrakiöğe. Böylece, listenin tüm öğeleri sıralanır. Bununla birlikte, doğrusal tekil bağlantılı bir listeyi işlemek her zaman uygun değildir, çünkü ters yönde hareket etme olasılığı yoktur - listenin sonundan başına. Doğrusal bir listede, ilk öğeden başlayarak, yalnızca geçerli öğeden diğerine sırayla hareket ederek tüm öğeleri gözden geçirebilirsiniz, doğrudan erişim ben-th öğesi mümkün değildir.

Örnek 1. Kütüphanecinin bilgisayarındaki okuyucuların soyadlarının kayıt sırası "önceki-sonraki" ilişkisini belirler. Kural olarak, kayıtların kendilerine ek bir özelliği vardır - bunlar alfabetik olarak sıralanır. Yeni bir okuyucu ekleme ve gerekirse eskisini silme işlemleri bu listenin üzerinde uygulanmaktadır. Buna ek olarak, her okuyucuya verilen defterlerin kayıtları tutuluyorsa, bu tür her bir kaydın, çıkarılan kitapların bir listesi kullanılarak tekrar temsil edilmesi uygundur.

Zil Listeleri- doğrusal bir liste ile aynı yapı, ancak son ve ilk eleman arasında ek bir bağlantı ile, yani ilk eleman son elemandan sonrakidir.

Doğrusal bir listenin aksine dairesel bir listede tüm elemanlar eşittir(çünkü her eleman için hem önceki hem de sonraki elemanlar tanımlanmıştır). Halka listesindeki "ilk" ve "son" öğelerin seçimi oldukça keyfidir, çünkü aslında liste yapısında açıkça vurgulanmış öğeler yok!

Örnek 2. Birçok oyunda çocuklar bir lider seçmek, takımlara ayrılmak vb. için sayma sayaçlarını kullanırlar. Kural olarak, tekerlemeleri saymak uzundur ve çocuklar (bilmeden) bir zil listesi düzenler. Önceki-sonraki ilişkisi liderin ne şekilde düşündüğü ile belirlenir. Böyle bir yapıdaki tipik bir işlem, halka yapısını korurken bir öğeyi listeden çıkarmaktır.

Öğelerin değerlerine ekleme, silme ve erişim işlemlerinin yalnızca uç öğelerle (ilk veya son) gerçekleştirildiği doğrusal listeler özel adlar almıştır.

Yığın- iki işlemin tanımlandığı doğrusal tek bağlantılı listenin özel bir durumu: yığının tepesine bir öğe ekleme (ilk öğeden önce) ve yığının tepesinden bir öğeyi kaldırma (ilk öğeyi kaldırma).

Örnek 3. Aritmetik ifadede çeşitli türlerdeki parantezlerin dengesini belirleme problemini düşünün. Örneğin, parantez ve köşeli parantez içeren bir ifadedeki parantezlerin dengeli olup olmadığını analiz etmek istiyorsunuz:? Bu sorunu çözmek için dinamik yapıyı kullanacağız. veri yığın... Bu problemi adım adım çözmek için bir algoritma verelim. Aşağıdaki gösterimi kullanacağız:

ben- analiz edilen sembolün numarası;

n- ifadedeki karakter sayısı.

1. ben = 0.

2. ben = ben + 1.

3. Eğer benn, sonra madde (4)'e gidin, aksi takdirde yığın boşsa, "parantezler dengelenir" mesajını veririz, aksi takdirde " mesajını veririz. parantezler dengeli değil”. Algoritmanın sonu.

4. Eğer ben-th karakteri parantezlerden farklıdır, sonra madde (2)'ye gidin.

5. Eğer ben-th karakter “(” veya “[”), sonra onu yığına koyarız, madde (2)'ye gideriz.

6. Eğer ben-th karakter “)” ise, yığının üstünü kontrol ederiz: yığının üstü “(” ise, onu yığından çıkarırız; madde (2)'ye gidin, aksi takdirde “ mesajını veririz. parantezler dengeli değil”. Algoritmanın sonu.

7. Eğer ben-th karakter “]” ise, yığının üstünü kontrol ederiz: yığının üstü “[” ise, onu yığından çıkarırız; (2) numaralı maddeye gidin, aksi takdirde “mesajını veririz” parantezler dengeli değil”. Algoritmanın sonu.

Sıra- yalnızca iki işleme izin verilen doğrusal tek bağlantılı listenin özel bir durumu: sıranın sonuna (kuyruğuna) bir eleman eklemek ve kuyruğun başından (başından) bir eleman çıkarmak.

Kuyruk kavramı, yaygın olarak kullanılan “sıra” terimine gerçekten çok yakındır. Bir mağazadaki müşteri kuyruğu, bu veri yapısı açısından iyi tanımlanmıştır.

Ağaçlar

Odun adı verilen bir öğeler topluluğudur. düğümler, bir öğenin seçildiği ( kök) ve öğelerin geri kalanı, her biri bir ağaç olan ve her bir alt ağacın kökü olan ayrık kümelere (alt ağaçlar) bölünür. azalan ağacın kökü, yani. tüm öğeler bir ebeveyn-çocuk ilişkisi ile bağlantılıdır. Sonuç olarak, hiyerarşik bir düğüm yapısı oluşur. Çocuğu olmayan düğümlere denir. yapraklar... Ağaçta şu işlemler tanımlanmıştır: ağaca eleman eklemek, ağaçtan eleman çıkarmak, ağaçta gezinmek, ağaçta eleman aramak.

Örnek 4. Bir ağaç, iki kişi arasındaki ilişkinin derecesini belirleme problemini çözebileceğiniz bir aile ağacını temsil etmek için en uygun veri yapısıdır.

Ağaçlar, oyunlarda kazanma stratejisini belirlemek için de kullanılır (bkz. “ Oyunlar. Kazanma stratejileri"), Ve çeşitli bilgi modelleri oluşturmak için (bkz. bilgi modelleri”).

Bilgisayar biliminde özellikle önemli bir rol, sözde tarafından oynanır. ikili ağaçlar.

İkili (ikili) ağaç- her düğümün, sol ve sağ alt ağacın kökleri olan en fazla iki torun sahibi olabileceği özel bir ağaç durumu.

Ek olarak, ağacın düğümleri için, sol alt ağacın öğelerinin tüm değerlerinin ağacın kökünün değerinden daha az olması koşulu sağlanırsa ve öğelerin tüm değerleri sağ alt ağaç kökün değerinden büyükse, böyle bir ağaç denir ikili arama ağacı ve öğeleri hızlı bir şekilde bulmak için tasarlanmıştır. Böyle bir ağaçta arama algoritması şu şekilde çalışır: İstenilen değer ağacın kökünün değeri ile karşılaştırılır ve karşılaştırmanın sonucuna göre arama sadece solda veya sadece sağda biter veya devam eder. sırasıyla alt ağaç. Karşılaştırma işlemlerinin toplam sayısı, sözde ağaç yüksekliği- ağacın kökünden yapraklardan birine giden yoldaki maksimum eleman sayısı. Yani, şekilde gösterilen ağacın yüksekliği 4'tür.

grafikler

grafik olarak adlandırılan bir öğeler kümesidir. zirveler olarak adlandırılan bu düğümler arasındaki bir dizi ilişki ile birlikte grafik pirzola grafik. Bu veri yapısının grafiksel yorumu, bazı çiftleri kenarlara karşılık gelen çizgiler veya oklarla birbirine bağlanan köşelere karşılık gelen bir dizi noktadır. İkinci durumda, grafik denir odaklı(ayrıca bkz. makaleler " Grafik modeller" ve " Tablo Modeller”).

Grafiklerin keyfi yapıdaki nesneleri tanımlamak için kullanılabilmesi nedeniyle, grafikler karmaşık nesnelerin yapılarını ve sistemlerin işleyişini tanımlamanın ana yoludur. Örneğin, bir bilgisayar ağını, taşıma sistemini, hiyerarşik yapıyı tanımlamak için (bir ağaç, bir grafiğin çeşitlerinden biridir). Algoritmaların blok diyagramları (bkz. “ Algoritma yazma yöntemleri”) Ayrıca grafiklerdir.

Ayrıca, her kenara belirli bir sayı atanmışsa ( ağırlık), o zaman böyle bir grafik denir dengeli... Örneğin, Rusya'da bir yol sistemini bir grafik kullanarak tanımlarken, belirli yerleşim yerlerini (grafiğin köşeleri) birbirine bağlayan yolun uzunluğu (grafiğin kenarının ağırlığı) önemlidir. Bu durumda, şekilde, yol haritasının aksine, karşılık gelen kenarların uzunluklarının kendilerine atanan ağırlıklara karşılık gelmesi gerekmez.

Örnek 5. Ağırlıklı bir grafik açısından, aşağıdaki problemi çözmek uygundur. Rus hükümeti, nüfusu bir milyonu aşan şehirleri birbirine bağlayan modern otoyolların inşası için bir plan hazırlıyor. Böyle bir şehirden başka bir şehre yeni otoyollarla gidilebilmesi ve toplam yol uzunluğunun minimum olması için ne tür yollar yapılmalı?

Grafik teorisindeki bu problemin basit ve kesin bir çözümü var. Herhangi bir şehirden yola çıkarak yol ağını planlamaya başlayabiliriz, örneğin St. Petersburg. En yakın milyon artı şehir ile bağlayalım. Ayrıca, her adımda, mevcut ağa en kısa yol eklenir, bu da henüz ağa bağlı olmayan bir şehri ağa dahil olan şehirlerden biriyle bağlayabilir. Böylece yol sayısı şehir sayısından bir eksik olacaktır.

Soyut bir veri yapısı - bir grafik - bir programda çeşitli şekillerde temsil edilebilir, yani. farklı veri türleri kullanır. Örneğin, bir grafik, her bir kenarı bir çift köşe ve gerekirse bir ağırlık ile belirten bir kenar listesi kullanılarak tanımlanabilir. En yaygın olanı, grafiğin tablo halinde depolanmasıdır (bkz. “ Tablo Modeller"), Olarak da adlandırılır komşuluk matrisi, yani iki boyutlu bir dizi, diyelim A, burada ağırlıksız bir grafik (veya 1) için, eğer köşeler arasındaki kenar ben ve J var ve (veya 0) aksi takdirde. Ağırlıklı bir grafik için A[ben][J], karşılık gelen kenarın ağırlığına eşittir ve bir dizi problemde bir kenarın yokluğu, uygun bir şekilde sonsuz ile gösterilir. Yönsüz grafikler için, bitişiklik matrisi her zaman ana köşegene göre simetriktir ( ben = J). Komşuluk matrisini kullanarak, grafiğin tepe noktasını bağlayan bir kenar içerip içermediğini kontrol etmek kolaydır. benüst ile J... Başlıca dezavantajı, bitişiklik matrisinin depolamak için yeterli bellek gerektirmesidir. n içeren bir grafik için 2 değer n köşeler, grafikteki kenarlar önemli ölçüde daha küçük olsa bile n 2 .

Kavramı açıklarken veri yapıları aşağıdaki çizimi kullanabilirsiniz.

Herhangi bir sorunu çözerken, birlikte çalışmak gerekli hale gelir. veri ve üzerlerinde işlemler yapmak. Genel olarak konuşursak, her görev için bu işlemler kümesi farklıdır. Bununla birlikte, çeşitli problemlerin çözümünde sıklıkla belirli bir işlem dizisi kullanılıyorsa, bu işlemleri mümkün olduğunca verimli bir şekilde gerçekleştirmenize izin veren verileri düzenlemenin bir yolunu bulmak yararlıdır. Böyle bir yöntem icat edildikten sonra, belirli bir problemi çözerken, hakkında bir tür veri depoladığı bilinen bir “kara kutumuz” (buna veri yapısı diyeceğiz) olduğunu varsayabiliriz. bu veriler üzerinde bazı işlemler gerçekleştirebilir. Bu, aklınızı ayrıntılardan çıkarmanıza ve sorunun göze çarpan özelliklerine odaklanmanıza olanak tanır. İçeride (yani bir bilgisayarda) bu "kara kutu" farklı şekillerde uygulanabilir ve en verimli (hızlı ve ekonomik bellek tüketen) uygulama için çaba göstermelisiniz.

Devlet eğitim standardı, hem temel okulun temel dersinde hem de lisede çeşitli veri yapılarının incelenmesini sağlar. Temel okul programlama kursunda, Örnek Program karakter dizilerinden (dizeler), sayılardan, listelerden, ağaçlardan ve grafiklerden işlenmiş nesneler olarak bahseder. Ancak pratik çalışmalarda, karmaşık bir yapının verilerinden sadece bir diziden bahsedilir (bkz. dizi işlemleri”). Temel okulda, grafik ve diğer modelleri oluştururken ilk etapta yapıların geri kalanını incelemek mantıklı görünüyor (ansiklopedinin IV. bölümüne bakın).

Uzman bir okul için örnek bir program sayılar, matrisler, diziler, listeler ve ağaçlarla çalışmayı içerir. Listelerle çalışmanın basit bir örneği olarak, yığını tek boyutlu bir dizi ve yığının üstüne işaret eden bir tamsayı değişkeni kullanarak düzenlemeyi seçebilirsiniz (yığın "alt" her zaman dizinin ilk öğesindedir) ). Makalede verilen parantezleri denge için kontrol etme sorununa ek olarak, bir aritmetik ifadeyi ters Lehçe notasyonuna çevirmek için bir algoritma örneğini kullanarak yığın hesaplayıcısının çalışmasını inceleyebilirsiniz ( son düzeltme kayıt) her zamanki halimizden infix aritmetik ifadenin değerinin kayıtları ve daha fazla hesaplanması.

Bir ikili ağacın tek boyutlu bir dizi kullanarak bilgisayar belleğinde temsil edilmesi de kolaydır, dizinin ilk elemanı ağacın kökünü ve ağaç düğümünün torunlarını depolar. ben dizinin inci elemanı 2'de yer alacak ben-m ve (2 ben+ 1) sırasıyla inci elemanlar. Düğümün çocuğu yoksa, karşılık gelen öğe, örneğin 0'a eşit olacaktır. Özyinelemeli ağaç geçiş prosedürü T ve bu durumda öğelerini yazdırmak şöyle görünecektir:

prosedür sırası (i: tamsayı);

Eğer t [i]<> 0 sonra

Dinamik değişkenler kullanarak listelerin ve dizilerin uygulanması hakkında, örneğin, klasik N. Wirth “Algoritmalar ve Veri Yapıları” kitabında okuyabilirsiniz.

Profil okulu müfredatına grafik algoritmaları da dahil edilmiştir. Özellikle bir grafikte en kısa yolu bulmaktan bahseder. Ağırlıksız bir grafik için, bu problem, örneğin, ilk önce bir kenarla orijinal tepe noktasına bağlanan grafiğin köşeleri işaretlendiğinde, daha sonra işaretlenenlere bağlı tüm köşeler işaretlendiğinde, genişlik öncelikli arama algoritması kullanılarak çözülebilir, ve bunun gibi. Ağırlıklı bir grafik için, Dijkstra'nın algoritması en sık kullanılır (örneğin, E.V. Andreeva'nın “Bilişim Olimpiyatları. Zirveye Giden Yollar”, “Bilişim” No. 8/2002 makalesine bakın). Bilgisayar bilimlerindeki Olimpiyat problemlerinin başarılı bir şekilde çözülmesi için bu tür algoritmaların bilgisi gereklidir. Bu nedenle, Bilişim 2007'deki Tüm Rusya Olimpiyatının IV federal bölge aşamasında, çözümü ağırlıklı bir grafikte en kısa yolu aramak olan “Hendekler ve Siperler” sorunu önerildi.

Başlangıçta programlama süreci, programcıya tüm algoritmaları doğrudan makine dilinde yazmasını sağladı. Bu yaklaşım, zaten zor olan algoritma geliştirme görevini daha da kötüleştirdi ve çoğu zaman, işin tamamlanmış olarak kabul edilebilmesi için keşfedilmesi ve düzeltilmesi [hata ayıklama olarak bilinen bir süreç] gereken hatalarla sonuçlandı.

Programlama görevini kolaylaştırmaya yönelik ilk adım, komutları ve işlenenleri doğrudan makinede kullanıldıkları biçimde yazmak için sayıların kullanımını ortadan kaldırmaktı. Bu amaçla, programların geliştirilmesinde, çeşitli komutların onaltılık gösterimleri yerine anımsatıcı gösterimlerini yaygın olarak kullanmaya başladılar. Örneğin, programcı kayıt yükleme komutunun dijital kodu yerine artık LOD yazabilir ve kaydın içeriğini belleğe kopyalamak için komut kodu yerine, anımsatıcı gösterim STO'sunu kullanabilir. İşlenenleri yazmak için, bir programcının bazı bellek bölgelerine açıklayıcı adlar atayabileceği [bunlara genellikle tanımlayıcılar denir] ve bunları program komutlarını yazarken karşılık gelen bellek hücrelerinin adresleri yerine kullanabileceği kurallar geliştirildi. Bu tür tanımlayıcılara genellikle değişkenler denir. Bu, belleğin belirli bir bölümünde tahsis edilen değeri değiştirerek, programın yürütülmesi sırasında bu bölüme atanan tanımlayıcı ile ilişkili değeri değiştirdiğimizi vurgular.

Bir programda bir değişken bildirildiğinde, türü genellikle aynı anda belirlenir. Veri türü, hem belirli verilerin yorumlanmasını hem de üzerinde gerçekleştirilebilecek işlemleri belirler. Veri türleri arasında Tamsayı, Gerçek, Karakter ve Boole bulunur.

Tamsayı türü, tamsayı olan sayısal verileri belirtmek için kullanılır. Bellekte, çoğunlukla ikili sistemin tamamlayıcı kodunda temsil edilirler. Tamsayı veriler üzerinde ortak aritmetik ve karşılaştırma işlemleri yapabilirsiniz.

Gerçek türü, tamsayı olmayan değerler içerebilen sayısal verileri temsil edecek şekilde tasarlanmıştır. Genellikle bellekte ikili kayan nokta sayıları olarak depolanırlar. Gerçek veriler üzerinde yapılabilecek işlemler, Tamsayı veriler üzerinde yapılanlara benzer. Ancak, Real türünde iki veri öğesi eklemek için gerçekleştirilmesi gereken işlemler, Tamsayı türündeki değişkenler üzerinde eylemler gerçekleştirmek için gereken işlemlerden farklıdır.

Karakter türü, bellekte ASCII veya UNICODE kodları olarak saklanan karakterlerden oluşan veriler için kullanılır. Bu tür veriler birbirleriyle karşılaştırılabilir [iki karakterden hangisinin diğerinden önce geldiğini alfabetik sırayla belirleyin]; bir karakter dizisinin başka bir karakter dizisi olup olmadığını kontrol edin ve ayrıca iki diziyi tek, daha uzun bir dizide birleştirin ve birini diğerinden [birleştirme işleminden] sonra ekleyin.

Boolean, yalnızca True ve False olmak üzere iki değere sahip olabilen verileri ifade eder. Bu tür verilere bir örnek, iki sayıyı karşılaştıran bir işlemin sonucudur. Boolean veri işlemleri, bir değişkenin geçerli değerinin True veya False olup olmadığının kontrol edilmesini içerir.

Makinenin ana belleği, sırayla artan adreslere sahip ayrı hücreler şeklinde düzenlenmiştir. Ancak, bu hücreler genellikle diğer veri yerleştirme yöntemlerini uygulamak için bir temel olarak kullanılır. Örneğin, metin genellikle uzun bir karakter dizisi olarak görülürken, satış bilgileri, her biri belirli bir çalışanın belirli bir günde yaptığı anlaşmaların sayısını temsil eden, sayısal değerlerin dikdörtgen bir tablosu olarak görüntülenebilir. Buradaki zorluk, makinenin ana belleğindeki gerçek veri organizasyonunun ayrıntılarını araştırmak yerine, kullanıcıya bu tür soyut yapıları manipüle etme araçlarını sağlamaktır. Bir bilgisayarı doğru kullanmak için, veriler arasındaki yapısal ilişkiler, bir bilgisayardaki yapıları temsil etmenin temel yöntemleri ve bunlarla çalışma yöntemleri hakkında iyi bir bilgiye sahip olmak gerekir. Bir bilgisayardaki veriler arasındaki bağlantılar için şu bilgi yapıları kullanılır: dizi, kayıt, liste, ağaç, yığın, sıra.

diziler

Dizi, aynı türden birkaç öğe içeren bir yapıdır. Dizin öğelerini sıralamak için dizinler kullanılır. Dizinler dizi adından sonra parantez içinde yazılır. Bir indeksli diziye tek boyutlu, iki indeksli diziye iki boyutlu denir ve bu böyle devam eder.

Kayıt

Kayıt, aynı türden olması gerekmeyen bir yapıdır. Bir kaydın bireysel öğelerine alanlar denir. Alan, sırayla, bir rekor da olabilir.

kayıt Öğrenci (
İlk adı,
Soy isim,
Grup
)

Listeler

Liste, her biri özel bir alan - bir işaretçi içeren bir dizi kayıttır. İşaretçi, bir kaydı başka bir kayıtla ilişkilendirir veya işaretçinin değerinin tanımsız olduğunu gösteren Null değerler içerir.

Tek başına bağlantılı bir listedeki girişlerin her birinde bir işaretçi bulunur ve bunlar bir zincir halinde bağlanır:

Şekildeki ok, işaretçinin içeriğinden bahseder ve Veri kelimesi, verilerin depolandığı alan koleksiyonlarını belirtir. Liste, ilk indeksi 0'a eşit olan tüm elemanların veri depolaması amaçlandığı ve ilk indeksi 1'e eşit olan elemanların işaretçi olduğu iki boyutlu bir dizi kullanılarak düzenlenebilir.


Bu listede İngiliz alfabesinin harflerini içeren girişler alfabetik sıraya göre düzenlenmiştir. Listedeki ilk giriş "A" karakterini, ikincisi "B" karakterini vb. içerir.

Bir listeyle çalışmak için üç temel işlemi yapabilmeniz gerekir:

Geçiş () - listede gezinme veya hareket etme;
Ekle () - listeye yeni bir giriş ekleme;
Sil () - listeden bir girişi siler.

Listeyle çalışmak için işlemlere ek olarak, iki değişken daha gereklidir:

listedeki ilk girişle ilgili bilgileri depolayan değişken Head
Listedeki geçerli girişi işaret eden Current değişkeni

Tablo, uygulama örneği yukarıda verilen listedeki bazı işlemlerin açıklamalarını özetlemektedir.

operasyon adısözde kod
Listede bir adım aşağı git

fonksiyon Geçiş (Akım) (
eğer (M Null) ise Akım: = M;
dönüş (Akım);
}

fonksiyon Ekle (Mevcut, Yeni) (
M: = M;
M: = Yeni;
dönüş;
}

Yeni değişken tarafından işaret edilen girişi listeye ekleyin

işlev Sil (Geçerli) (
eğer (M Null) o zaman
M: = M];
dönüş;
}

Çift bağlantılı bir listedeki kayıtlar bir zincirde birbirine bağlanır, ancak aynı zamanda iki işaretçi alanına sahiptirler. Biri listedeki bir önceki öğeye, diğeri bir sonraki öğeye işaret eder. Bu yapı, listede iki yönde ilerlemenizi sağlar: ileri ve geri.

Dairesel liste, son girişi birinciyi gösteren bir listedir. Bu listelerde boş giriş yok.


Ağaç, her biri birden çok işaretçi içerebilen dallanmış bir listedir. Ağaçtaki girişlere düğüm denir. Tüm işaretçilerin boş olduğu düğümlere yaprak denir. Ağacın en üstteki başlangıç ​​düğümüne kök düğüm denir. Birçok problemde, düğümleri ikiden fazla işaretçiye sahip olmayan ikili [ikili] ağaçları kullanmak yeterlidir.

Örnek. Matematiksel ifadeyi (3 + 7) * (2 / (3-1)) değerlendirmek istiyorsunuz. Bu ifadeyi bir ağaç olarak gösterelim:

Bu ağacın her bir düğümü aşağıdaki formun bir kaydıdır:

kayıt Düğümü (
Operasyon
Sayı
Solİşaretçi
Sağİşaretçi
)

Ağacın yaprakları sayıları içerir, geri kalan düğümler işlemlerin sembolleridir.

Tanımlanan ağacı iki boyutlu bir diziye uyguladıktan sonra aşağıdaki resmi elde ederiz:


Bir ağacın değerini hesaplamak için sağ ve sol alt ağaçların değerlerini hesaplamanız ve ardından bunlar üzerinde ortaya çıkan işlemi gerçekleştirmeniz gerekir. Problemi çözen algoritmanın sözde kodu şöyle görünecektir:

function Hesapla (Akım) (
eğer (M = Boş) o zaman
Sonuç: = M;
Başka (
R1: = Hesapla (M);
R2: = Hesapla (M);
Sonuç: = R1 (M) R2;
}
dönüş (Sonuç);
}

Yığın, son giren ilk çıkar veri yapısıdır. Yığında depolanan verilere üstten erişilir. Veriler yığına sırayla itilir.Yığına ilk önce itilen eleman en alttadır ve onu yığından çıkarmak için önce yığına itilen tüm verileri daha sonra açmanız gerekir.

Bir yığınla çalışırken, iki acil durum mümkündür: boş bir yığından veri okuma girişimi; Yığındaki öğe sayısı izin verilen maksimum sayıya ulaştığında, bir öğeyi yığına itme girişimi.

Kuyruk, ilk giren ilk çıkar veri yapısıdır. Kuyrukta değişken miktarda veri var. Kuyruğa alındığında veriler kuyruğa eklenir, alındığında ise head kısmından alınır.

karma tablo

Hashing, herhangi bir ek yapı kullanmadan kayıtlara doğrudan erişim sağlayan bir tekniktir. Süreç aşağıdaki gibi özetlenebilir. Verilerin depolandığı alan birkaç bölüme ayrılmıştır. Kayıtlar, anahtar alanın değerini bir segment numarasına dönüştüren, hashing algoritması adı verilen bir algoritmaya göre bu segmentler arasında dağıtılır. Her kayıt, bu süreç tarafından tanımlanan bir segmentte saklanır. Bu nedenle, bir kayıt, anahtar alanının değeri hash edilerek ve ilgili segmentin kayıtları okunarak alınabilir. Bu şekilde oluşturulan bir veri yapısına karma tablo denir.

Örneğin, İngiliz alfabesinin büyük harflerini depolamak için bir karma tablo düzenlemeniz gerekiyorsa, anahtar olarak ASCII karakter kodlarını seçebilirsiniz ve karma algoritması en az anlamlı beş biti kesecek ve depolama için bir dizi öğe indeksi oluşturacaktır. karakter onların temelinde:

Genel olarak, bir karma algoritma, anahtar değerine dayalı olarak, dizinin sınırları içinde bir dizin değeri üretmeli ve anahtarları dizi öğeleri arasında eşit olarak dağıtmalıdır. Son gereksinime uyulmaması, birkaç kaydın aynı segmente girdiği durumlara yol açar. Bu durumlara çarpışma denir.

Bu makalenin konusu yine programlama teorisi, bu yüzden farklı sınıflandırmalara başvurmanız ve matematiksel terimlerle işlem yapmanız gerekecektir. Veri yapıları, pratikte eğitim sırasında tartışılan ilk şeydir. Algoritmaların karmaşıklığının tahmini ikincisidir. Bu iki sorunun çok az bağlantısı var gibi görünebilir, ancak değildirler ve hikaye ilerledikçe bunun nedeni anlaşılacaktır. Ayrıntılara girmeyeceğim, çünkü uygulama, deneyim kazanma sürecinde sadece en önemlisinin kafada kaldığını gösteriyor. Bence bu, herhangi bir faaliyet alanında olur. Bu konularda kafamda kalanları özetlemeye çalışacağım.

Veri yapılarının sınıflandırılması

Veri yapısı Bir bilgi depolama ve sunum şeklidir. Tanım oldukça belirsizdir, bu nedenle uzmanlar çeşitli sınıflandırma ve iyileştirme biçimleri kullanır. Veri yapıları basit ve karmaşıktır: atomik bir bilgi birimini veya aynı türden bir veri kümesini temsil ederler. Basit veri yapıları, örneğin tamsayı, gerçek, boole, metin türü vb. ile karakterize edilir. Karmaşık veri yapıları dinamik ve statik kümelere ayrılır. Dinamik olanlar, yaşam döngüleri boyunca boyutlarını değiştirmenize (eleman ekleme ve çıkarma) izin verirken, statik olanlar buna izin vermez. Ve son olarak, karmaşık veri yapılarının öğeleri arasındaki ilişkilerin organizasyonuna göre, aşağıdaki sınıflandırma vardır:

  • Doğrusal
    • Dizi
    • Liste
    • Bağlantılı liste
    • Sıra
    • karma tablo
  • Hiyerarşik
    • ikili ağaçlar
    • N-ary ağaçları
    • hiyerarşik liste
    • Basit grafik
    • Yönlendirilmiş grafik
  • tablo şeklinde
    • İlişkisel veritabanı tablosu
    • iki boyutlu dizi
  • Başka
  • Verilen sınıflandırma tam olmaktan uzaktır. Karmaşık veri yapılarının öğeleri, örneğin bir veri yapısı gibi hem basit hem de karmaşık veri yapılarının örnekleri olabilir. OrmanÖrtüşmeyen ağaçların bir listesidir. Şimdi karmaşık veri yapılarının listelenen sınıflarının kısa bir tanımını vermeye çalışacağım. Sınıflandırmanın ilk seviyesi, bir dizi karmaşık veri yapısındaki bireysel öğeleri arama ve adresleme şeklindeki farklılıklara dayanır.

    Doğrusal veri yapıları

    Doğrusal bir veri yapısının bir öğesi, doğrusal bir öğe dizisindeki bir seri numarası veya indeks ile karakterize edilir.

    Dizi- İçinde statik doğrusal yapı aynı türden Endeksine göre bir öğeyi bulma işlemleri için optimize edilmiş veriler. Bir elemanın bellekteki kesin konumu, tam olarak dizideki elemanların tekdüzeliği ile sağlanır ve indeksinin çarpımı ve bir eleman tarafından işgal edilen belleğin boyutu tarafından belirlenir.

    Doğrusal dizi.
    Adres (eleman (dizin)) = hücre_boyutu * dizin.

    Liste Her öğenin yalnızca bir öncekine atıfta bulunduğu dinamik bir doğrusal veri yapısıdır - tek yönlü doğrusal liste, veya önceki ve sonrakine - çift ​​yönlü doğrusal liste... Bu veri yapısının güzelliği, yeniden boyutlandırılabilir olmasının yanı sıra, uygulama kolaylığıdır. Ayrıca, referansların varlığı nedeniyle, bir diziden farklı olarak listedeki her öğe farklı miktarda bellek kaplayabilir. Doğrusal bir listedeki ilk öğenin adresi, listenin kendisinin adresi tarafından benzersiz bir şekilde belirlenir.

    Bağlantılı listeÖğe eklemek ve çıkarmak için optimize edilmiş, normal bir doğrusal listenin bir çeşididir. Optimizasyon, bağlantılı listenin öğelerinin bellekte birbiri ardına yerleştirilmesi gerekmemesidir. Öğelerin sırası, ilk öğeye yapılan referansla (liste için ayrılan belleğin en başında olması gerekmez) ve listenin geri kalan öğelerine yapılan başvuruların sırası ile belirlenir.


    Bağlantılı liste.

    Yığın Bir öğe kümesini değiştirmek için yalnızca iki işlemin tanımlandığı dinamik bir doğrusal veri yapısıdır: sona öğe ekleme ve son öğeyi silme. Ayrıca yığının LIFO ilkesini (Son giren İlk Çıkar) - son giren ve ilk çıkar - uyguladığını söylüyorlar. Örneğin, bir program kodunun yürütülmesi sırasında, bir bilgisayar, bir prosedürü veya bir işlevi çağırmak gerekirse, ilk önce işaretçiyi yığındaki çağrısının yerine iter, böylece kodunun yürütülmesi tamamlandığında , çağrı noktasından sonra doğru bir şekilde sonraki talimata dönecektir. Bu veri yapısına alt rutin çağrı yığını denir.

    Yığın.

    Sıra- FIFO ilkesini (First in, First out) uygulaması arasındaki tek farkla çok benzer yığınsız, dinamik bir veri yapısı - ilk gelen ve ilk sol. Gerçek hayattaki örnekler için adından da anlaşılacağı gibi çok uzağa gitmenize gerek yok. Programlamada, örneğin kuyruklar, kullanıcı arabirimi olaylarını, istemci çağrılarını ve diğer bilgi isteklerini yönetir.

    Sıra.

    karma tablo Dinamik doğrusal veri yapısının en karmaşık türüdür. Karma tablosu, öğenin adresini bir karma değeri olarak hesaplayarak öğeleri hızlı bir şekilde bulmak için optimize edilmiştir. Karma işlevinin argümanı, örneğin sıra numarası gibi öğeyle ilişkili bir anahtardır. Benzersiz anahtar değerler için benzersiz karma değerleri garanti etmek için (çarpışmalardan kaçının), karma tablo, zor algoritmalara ek olarak, RAM'i de cömertçe kullanır. Hash tablolarının kullanımı gerekçelendirilmeli ve dikkatlice düşünülmelidir.

    Hiyerarşik veri yapıları

    Hiyerarşik bir veri yapısındaki bir öğe, hiyerarşideki bir üst düzey öğeye bağlantı (veya daha düşük düzeyli öğelere bağlantılar) ve (isteğe bağlı olarak) düzeyinin doğrusal dizisindeki bir sıra numarası (hiyerarşik listeler) ile karakterize edilir. .

    Ağaçlar- tek bir kök düğüm ve onun soyundan gelenler tarafından temsil edilen dinamik bir hiyerarşik veri yapısı. Her düğümün maksimum çocuk sayısı ve bir ağacın boyutu... Ayrı ayrı ayırt ikili veya ikili ağaçlar sıralama ve arama algoritmalarında kullanıldıkları için: ikili sistemin her bir düğümü arama ağacı sıralanmış bir kümeden bir öğeyi, tüm "sol" çocuklarını - daha küçük öğeleri ve tüm "sağ" çocuklarını - büyük öğelerle eşleştirir. Ağaçtaki her düğüm, kökten yola kadar tekrar etmeyen bir dizi düğüm tarafından benzersiz bir şekilde tanımlanır. Yol uzunluğu, ağaç hiyerarşisindeki düğümün düzeyidir. İkili veya ikili ağaçlar için aşağıdakiler ayırt edilir: özyinelemeli geçiş türleri tüm öğelerinin (küme parantezler, kökten başlayarak her düğümün öğelerini ziyaret etme sırasını gösterir):

    • doğrudan veya önek
      (düğüm, sol alt ağaç, sağ alt ağaç);

    • ters veya postfix
      (sol alt ağaç, sağ alt ağaç, düğüm);

    • simetrik veya infix
      (sol alt ağaç, düğüm, sağ alt ağaç);

    Öğeleri artan sırada listelemek için arama ağacında simetrik bir sırayla gezinin. Elemanların ters sırada görünebilmesi için geçiş sırasında alt ağaçların ziyaret sırasının değiştirilmesi gerekir.


    İkili (ikili) ağaç.

    hiyerarşik liste- doğrusal bir listenin ve bir ağacın simbiyozu. Listenin her öğesi aynı zamanda hiyerarşinin bir sonraki alt seviyesinin listesinin başlangıcı olabilir. Hiyerarşik listeye bir örnek, İnternet forumlarının yapısıdır: bir dizi mesaj doğrusal bir liste oluştururken, diğer mesajlara verilen cevaplar yeni tartışma konuları oluşturur.


    Hiyerarşik liste.

    Ağ veri yapıları

    Ağ veri yapısındaki bir öğe, diğer komşu öğelerle bir dizi bağlantı ile karakterize edilir. Bu tür veri yapılarında ne başlangıç ​​ne de kök öğe açıkça vurgulanmaz.

    grafik- bir dizi köşe ve kenar ile temsil edilen dinamik ağ veri yapısı - köşeler arasındaki bağlantılar. Her köşe noktası, herhangi bir sayıda başka köşeyle veya kendisiyle ilişkilendirilebilir. Artık burada net bir hiyerarşi yok. Ağacın düğümlerini grafiğin köşeleri olarak ve hiyerarşinin farklı seviyelerindeki ağacın düğümleri arasındaki bağlantıları da grafiğin kenarları olarak kabul edersek, ağacın kendisi bir grafik olarak kabul edilebilir. döngüler veya döngüsel olmayan bir grafik içerir. Grafiğin her kenarı için bir yön tanımlanmışsa, bu bir yönlendirilmiş grafiktir. Yöne ek olarak, grafiğin her kenarının kendi ağırlığı olabilir. Örneğin bir grafik yardımıyla ulaşım ağları modellenir ve trafik akış optimizasyonu sorunları çözülür. Yük veya tersine, taşıma yollarının verimi, karşılık gelen nervürlerin ağırlığı ile belirlenir.


    Grafik.

    Yönlendirilmiş grafik.

    Tablo veri yapısındaki bir öğe, iki boyutlu bir dizin ile karakterize edilir: satırın dizini ve kesiştiği noktada bulunan sütunun dizini. Tablo veri yapılarının örnekleri tablolardır.


    Algoritmaların karmaşıklığını tahmin etme

    Algoritmaların karmaşıklığının tahmini, yazarların geliştirmeleri için harcadıkları entelektüel çabalar değil, bir bilgisayar tarafından gerçekleştirilen temel işlemlerin sayısının işlenen bilgi miktarına bağımlılığı anlamına gelir. Örneğin, sıralama algoritmasının çalışması sırasında iki sayının karşılaştırma sayısının orijinal dizinin uzunluğuna nasıl bağlı olacağı. Tanımı bilerek biraz daralttım, çünkü aşağıda sadece temel işlemlerin sayısı hakkında konuşacağız. Aslında, algoritmanın karmaşıklığı yalnızca işlem sayısıyla değil, aynı zamanda sorunu çözmede yer alan bilgi işlem kaynaklarının miktarı ve her şeyden önce RAM ile belirlenir. Algoritma ne kadar basitse, çalışması o kadar olasıdır. Karmaşık ve hızlı algoritmalar genellikle yardımcı veri yapılarını kullanır ve sonuç olarak ek bellek tüketir. Enerjinin korunumu yasası veya “her şey için ödeme yapmanız gerekir”. Daha önce tartışılan "marjinal optimizasyon"un bir örneği, bir karma tablodur. Şahsen, hash tablosunun nasıl düzenlendiğini ve hash fonksiyonlarının nasıl göründüğünü bilmiyorum (sanırım kolay değil), ancak diğer yandan, anahtara göre eleman arama süresi pratik olarak tablonun boyutuna bağlı değil. İşte küçük bir teori.

    Algoritmaların karmaşıklığının tahmini, matematiksel aparat kullanılarak gerçekleştirilir. asimptotik analiz ve karmaşıklık için asimptotik bir tahminin türetilmesi.

    Asimptotik karmaşıklık tahmini Yunanca Θ (teta) harfi ile gösterilir.

    f (n) = Θ (g (n)) c1 * g (n) n0 olacak şekilde c1, c2> 0 ve n0 varsa.

    g (n) işlevi, algoritmanın karmaşıklığının asimptotik olarak doğru bir tahminidir - f (n) işlevi, yukarıdaki eşitsizliğe asimptotik eşitlik denir ve Θ gösteriminin kendisi, "hızlı" büyüyen işlevler kümesini sembolize eder. g (n) fonksiyonu, yani e. bir sabitle çarpmaya kadar. Yukarıdaki eşitsizlikten anlaşılacağı gibi, Θ tahmini aynı anda karmaşıklığın hem üst hem de alt sınırlarıdır. Bu formda puan almak her zaman mümkün değildir, bu nedenle üst ve alt tahminler bazen ayrı ayrı belirlenir.

    Üst zorluk tahmini Yunanca Ο (omikron) harfi ile gösterilir ve g (n)'den daha hızlı büyümeyen bir dizi fonksiyondur.

    f (n) = Ο (g (n)) 0n0 olacak şekilde c> 0 ve n0 varsa.

    Daha düşük karmaşıklık tahmini Yunanca Ω (omega) harfi ile gösterilir ve g (n)'den daha yavaş büyümeyen bir dizi fonksiyondur.

    f (n) = Ω (g (n)) ise 0n0 olacak şekilde c> 0 ve n0 varsa.

    Sonuç olarak: bir asimptotik tahmin, yalnızca algoritmanın karmaşıklığının alt ve üst sınırları çakışırsa var olur. Algoritmaları analiz etme pratiğinde, karmaşıklık tahmini çoğunlukla üst karmaşıklık tahmini olarak anlaşılır. Bu oldukça mantıklıdır, çünkü en önemlisi, algoritmanın kesinlikle tamamlayamayacağı süre değil, çalışmasını tamamlamayı garanti ettiği sürenin tahminidir.

    Doğrusal veri yapılarıyla çalışma

    Sonuç olarak, doğrusal veri yapılarıyla temel işlemlerin karmaşıklığı hakkında tahminler vereceğim, yani bir öğeyi indeks veya anahtar ile ekleme, silme ve arama. Bu durumda temel işlemler, karşılaştırma, numaralandırma, bir adresin hesaplanması veya bir veri yapısı kümesinin öğelerinin permütasyon işlemleridir. Pivot tabloda, üst karmaşıklık tahminine ek olarak, listelenen veri yapılarına karşılık gelen kitaplık bileşenleri de verilmektedir. Böylece temel lineer veri yapıları hazır ve platformdaki tüm yazılım geliştiricilerin kullanımına açıktır.


    Yapılar ve veri türleri. Diziler, ağaçlar, listeler, grafikler. Veri işlemleri.

    Bilgisayar belleğinde depolanan veriler, sıfırlar ve birler (bitler) topluluğudur. Bitler sırayla birleştirilir: baytlar, kelimeler vb. Bir bayt veya kelime alabilen RAM'in her parçasına bir sıra numarası (adres) atanır.

    Verilerin anlamı nedir, hangi sembollerle ifade edilirler - alfabetik veya sayısal, bu veya bu sayı ne anlama gelir - tüm bunlar işleme programı tarafından belirlenir. Pratik problemleri çözmek için gerekli tüm veriler birkaç türe ayrılır ve tür kavramı yalnızca verilerin adres alanındaki temsili ile değil, aynı zamanda bunları işleme yöntemiyle de ilişkilidir.

    Herhangi bir veri iki türden birine sınıflandırılabilir: biçimi bilgisayar mimarisi tarafından belirlenen temel (basit) veya belirli sorunları çözmek için kullanıcı tarafından tasarlanan karmaşık.

    Basit veri türleri semboller, sayılar vb. daha fazla ezilmesi mantıklı olmayan unsurlar. Veri yapıları (karmaşık tipler) temel verilerden oluşturulur.

    Bazı yapılar:

    Bir dizi (sonlu tanım alanına sahip bir işlev), aynı türdeki veri öğelerinin basit bir koleksiyonudur, aynı türdeki bir grup veriyle çalışma aracıdır. Dizinin tek bir elemanı bir indeks tarafından belirtilir. Bir dizi tek boyutlu, iki boyutlu vb. olabilir. Halka, yığın, kuyruk ve deque türleri, tek boyutlu değişken uzunluklu dizilerin tatlarıdır.

    Bir dizi her zaman bitişik bir bellek parçasını işgal ediyorsa, o zaman bir liste, sözde dinamik veri yapısının en basit örneğidir. Dinamik veri yapılarında, işlem sırasında sayısı ve bileşimi değişebilen çeşitli bellek alanlarında bir nesne bulunur. Böyle bir nesnenin birliği, parçalarının sınıf tanımında birleştirilmesiyle sağlanır.

    En basit doğrusal liste, öğelerin doğrusal bir dizisidir. Her biri için, sonuncusu hariç, bir sonraki öğe vardır ve her biri için, birincisi hariç - bir önceki. Liste geleneksel olarak, her biri bir sonraki ve / veya önceki öğeye bir bağlantı (işaretçi) içeren bir öğe dizisi olarak tasvir edilir, ancak liste öğelerinin temsilinde fiziksel olarak herhangi bir bağlantı olmayabileceğini unutmayın.

    Bir listedeki tipik bir işlem dizisi, öğelerini eklemeyi, kaldırmayı ve aramayı, listenin uzunluğunu hesaplamayı ve listenin öğelerini sırayla işlemeyi (yinelemeyi) içerir.

    Dizilerde olduğu gibi, birçok sınıf kitaplığı listeleri tanımlama ve değiştirme becerisine sahiptir (örneğin, MFC sınıf kitaplığının CList'i). Buna rağmen, kendi veri yapılarınızı, çözülmekte olan problem için daha uygun, standart olanlardan daha basit (ve dolayısıyla daha verimli) veya belirli özelliklerle (örneğin, sıralı) içeren listeler şeklinde tanımlamanız gerekir. listeler).

    Tipik olarak, bir liste açıklanırken, listedeki her bir öğenin temsili ayrı bir sınıf olarak tanımlanır. Bu sınıfın özniteliği olarak sonraki ve/veya önceki öğeye bir bağlantısı vardır.

    Kayıt (Kartezyen ürün) - farklı türlerdeki veri öğelerinin bir koleksiyonu. En basit durumda, bir kayıt, alanlar olarak adlandırılan sabit sayıda öğe içerir. Aynı yapıdaki kayıtların toplamına dosya denir. (Bir dosyaya, manyetik disk gibi harici bellekteki veri kümesi de denir). Dosyadan tek tek kayıtları çıkarabilmek için, her kayda, tanımlayıcı görevi gören benzersiz bir ad veya numara atanır ve ayrı bir alanda bulunur. Bu tanımlayıcıya anahtar denir.

    Dizi veya kayıt gibi veri yapıları, bilgisayar belleğinde sabit bir hacim kaplar, bu nedenle bunlara statik yapılar denir. Birçoğu da statik yapılara aittir.

    Uzunluklarını değiştirebilen bir dizi yapı vardır - sözde dinamik yapılar. Bunlar ağaç, liste, bağlantı içerir.

    Öğelerini yerleştirmek için doğrusal olmayan bir adres alanı gerektiren önemli bir yapı bir ağaçtır. Ağaç olarak temsil edilebilecek birçok veri yapısı vardır. Bunlar örneğin sınıflandırma, hiyerarşik, özyinelemeli ve diğer yapılardır.

    Genelleştirilmiş yapılar veya veri modelleri.

    Yukarıda, veri öğelerinin koleksiyonları olan çeşitli yapı türlerini ele aldık: dizi, ağaç, kayıt. Daha karmaşık bir veri türü, bu yapıları üye olarak içerebilir. Örneğin, bir kaydın öğeleri bir dizi, bir yığın, bir ağaç vb. olabilir.

    Çok çeşitli karmaşık veri türleri vardır, ancak geniş bir pratik malzeme üzerinde yürütülen çalışmalar, aralarında en yaygın olanlardan birkaçının ayırt edilebileceğini göstermiştir. Genel yapılara veri modelleri de denir, çünkü bunlar kullanıcının gerçek dünya verilerine bakışını yansıtırlar.

    Herhangi bir veri modeli üç bileşen içermelidir:

    Veri yapısı - verilerin sunumuna ilişkin kullanıcının bakış açısını tanımlar.

    Veri yapısı üzerinde gerçekleştirilen geçerli işlemler kümesi. Veri modeli, en azından, depolama yapılarını tanımlayan bir veri tanımlama dilinin (DLS) ve veri çıkarma ve değiştirme işlemlerini içeren bir veri işleme dilinin (MDL) varlığını varsayar.

    Bütünlük kısıtlamaları, resmi olarak tanımlanmış kurallara dayalı olarak etki alanı verilerinin tutarlılığını korumak için bir mekanizmadır.

    Tarihsel gelişim sürecinde VTYS'de aşağıdaki veri modelleri kullanılmıştır:

    Hiyerarşik - Bu modelde, bir ana nesne ve geri kalan - alt - hiyerarşinin farklı seviyelerinde bulunan nesneler vardır. Nesne ilişkileri, tek bir kök nesne ile hiyerarşik bir ağaç oluşturur.

    Ağa Bağlı - Verileri organize etmeye yönelik ağ bağlantılı yaklaşım, hiyerarşik olanın bir uzantısıdır. Hiyerarşik yapılarda, bir alt kaydın tam olarak bir ebeveyni olmalıdır; bir ağ veri yapısında, bir soyun herhangi bir sayıda ataya sahip olabilir.

    Ağ veri modelinde, herhangi bir nesne hem ana hem de bağımlı olabilir ve diğer nesnelerle herhangi bir sayıda ilişkinin oluşumuna katılabilir.

    İlişkisel - İlişkisel bir modelde, veriler tablo şeklinde bir yapı oluşturan kümelere bölünür. Bu tablo yapısı, alanlar adı verilen ayrı veri öğelerinden oluşur. Tek bir küme veya alan grubu, kayıt olarak bilinir.

    Veri erişim yöntemleri.

    Veri sunumu sorunları, bu verilerin işlendiği işlemlerle yakından ilgilidir. Bu işlemler, verilerin alınmasını, değiştirilmesini, dahil edilmesini ve hariç tutulmasını içerir. Yukarıdaki işlemlerin tümü, sunum yönteminden bağımsız olarak düşünülemeyecek olan erişim işlemine dayanmaktadır.

    Arama problemlerinde, tüm verilerin belirli bir kimlikle bellekte depolandığı varsayılır ve erişimden bahsetmişken, bunlar her şeyden önce, ilişkili veri kümelerini benzersiz bir şekilde tanımlayan verilere (anahtarlar olarak adlandırılır) erişim anlamına gelir.

    Her biri benzersiz bir anahtar alan değerine sahip olan bir dizi özdeş kayıt içeren bir dosyaya erişimi düzenlememiz gerektiğini varsayalım. Aramanın en kolay yolu, anahtar değeri arama kriterleriyle eşleşeni bulana kadar dosyadaki her kaydı sırayla taramaktır. Açıktır ki, dosyadaki kayıtlar anahtar alanının değerine göre sıralanmadığından bu yöntem oldukça verimsizdir. Bir dosyadaki kayıtları sıralamak da daha fazla zaman aldığından ve her kayıt eklendikten sonra yapılması gerektiğinden uygulanamaz. Bu nedenle, aşağıdaki gibi ilerlerler - anahtarlar, dosyadaki ilgili kayıtların işaretçileriyle birlikte, sıralama ve arama işlemlerini hızlı bir şekilde gerçekleştirmenizi sağlayan başka bir yapıya kopyalanır. Verilere erişilirken bu yapıda önce karşılık gelen anahtar değeri bulunur ve daha sonra onunla saklanan işaretçiden dosyadan bir kayıt alınır.

    Anahtar veri erişimini uygulayan iki yöntem sınıfı vardır:

    Ağaç arama yöntemleri,

    Hash yöntemleri.

    Grafik teorisi, hesaplamalı matematiğin önemli bir parçasıdır. Bu teorinin yardımıyla, çeşitli alanlardan çok sayıda problem çözülmüştür. Grafik, birçok köşeden ve köşeleri birbirine bağlayan birçok kenardan oluşur. Graf teorisi açısından, köşelere ve kenarlara ne anlam yüklendiği önemli değildir. Köşeler yerleşim olabilir ve onları birbirine bağlayan yolun kenarları veya köşeler alt rutinlerdir, köşeler tarafından kenarlarla birbirine bağlanır, alt rutinlerin etkileşimi anlamına gelir. Genellikle grafikteki yayın yönü önemlidir. Kenarın yönü varsa yay, kenarları yönlendirilmiş grafa digraf denir.

    Şimdi grafik teorisinin daha resmi olarak temel bir tanımını veriyoruz. G grafiği sıralı bir çifttir (V, E), burada V boş olmayan bir köşeler kümesidir, E, V kümesinin eleman çiftleri kümesidir ve V'den gelen bir eleman çiftine kenar denir. V'den sıralı bir eleman çiftine yay denir. E'deki tüm çiftler sıralanırsa, grafiğe yönlendirilmiş denir.

    Bir yol, bir digraftaki herhangi bir köşe dizisidir, öyle ki bu dizide, b köşesi a köşesini ancak a'dan b'ye kadar bir yay varsa izleyebilir. Benzer şekilde, yaylardan oluşan bir yol tanımlayabilirsiniz. Bir tepe noktasında başlayan ve bir tepe noktasında biten yola çevrim denir. Döngü olmayan bir grafiğe asiklik denir.

    Grafiğin önemli bir özel durumu ağaçtır.

    Tanım: Ağaç, düğüm adı verilen bir veya daha fazla öğeden oluşan sonlu bir kümedir, öyle ki:

    Düğümler arasında bir ebeveyn-çocuk ilişkisi vardır;

    Kaynağı olmayan tek bir düğüm vardır. Kök denir;

    Kök dışındaki tüm düğümlerin yalnızca bir kaynağı vardır; her düğümün birkaç çocuğu olabilir;

    Köken tarafından oluşturulan ilişki yalnızca bir yönde çalışır, yani. herhangi bir düğümün soyundan gelen kimse onun atası olamaz.

    Oluşturulan bireysel düğümlerin sayısına (belirli bir kökün alt ağaçlarının sayısı) derecesi denir. Sıfır dereceli bir düğüme yaprak veya uç düğüm denir. Belirli bir ağaçtaki tüm düğümlerin derecesinin maksimum değerine ağacın derecesi denir.

    Ortak bir kaynağa sahip, oluşturulan düğümler arasındaki bir ağaçta, sıraları gerekli kabul edilirse, ağaca sıralı denir. Arama problemlerinde, sıralı ağaçlar neredeyse her zaman dikkate alınır.

    Derecesi en fazla 2 olan sıralı ağaca ikili ağaç denir. İkili ağaç özellikle RAM'de arama yaparken kullanılır. Arama algoritması: ilk olarak, arama argümanı kökteki anahtarla karşılaştırılır. Argüman anahtarla eşleşirse arama biter, eşleşmezse arama sona erer, argümanın anahtardan küçük olması durumunda arama sol alt ağaçta, anahtardan fazla olması durumunda arama devam eder. sağ alt ağaçta. Seviyeyi 1 arttırmak, mevcut düğümü kök olarak kabul ederek karşılaştırmayı tekrarlayın.

    İkili ağaçlar, özellikle anahtar kümesinin önceden bilinmediği veya bu kümenin hızla değiştiği durumlarda etkilidir. Açıkçası, değişken bir anahtar seti ile dengeli bir ağaca sahip olmak daha iyidir.

    Tanım: Her düğümün sol alt ağacının yüksekliği, sağ alt ağacın yüksekliğinden en fazla 1 farklıysa, ikili ağacın dengeli olduğu söylenir.

    Hashing.

    Bu yöntem, tüm anahtar kümesi önceden bilindiğinde kullanılır ve işlem süresi boyunca RAM'de bulunabilir. Bu durumda, bir dizi anahtarı benzersiz bir şekilde bir dizi işaretçiye eşleyen özel bir işlev oluşturulur, buna karma işlevi denir (İngilizceden "karma" - kesme, öğütme). Böyle bir fonksiyona sahip olmak, verilen arama anahtarına göre dosyadaki kaydın adresini hesaplamak mümkündür. Genel olarak, bir kaydın adresini belirlemek için kullanılan anahtar veriler, karma tablo adı verilen bir tabloda düzenlenir.

    Anahtar kümesi önceden bilinmiyorsa veya çok büyükse, o zaman bir kaydın adresini anahtarıyla açık bir şekilde hesaplama fikri terk edilir ve karma işlevi basitçe bir dizi anahtarı dağıtan bir işlev olarak kabul edilir. bir dizi adres.

    • Tercüme

    Elbette, veri yapılarının kutsal bilgisine sahip olmadan başarılı bir programcı olabilirsiniz, ancak bazı uygulamalarda kesinlikle yeri doldurulamazlar. Örneğin, bir haritadaki iki nokta arasındaki en kısa yolu hesaplamanız veya örneğin bir milyon giriş içeren bir telefon defterinde bir isim bulmanız gerektiğinde. Bahsetmemek gerekirse, veri yapıları spor programlamasında sürekli olarak kullanılmaktadır. Bazılarını daha ayrıntılı olarak ele alalım.

    Sıra

    Öyleyse Loopy'ye merhaba deyin!

    Loopy ailesiyle hokey oynamayı seviyor. "Oynat" derken şunu kastediyorum:

    Kaplumbağalar kapıya uçtuğunda yığının tepesine atılırlar. Yığına eklenen ilk kaplumbağanın ilk ayrılan olduğuna dikkat edin. denir Sıra... Tıpkı günlük hayatta gördüğümüz sıralarda olduğu gibi, listeye ilk eklenen madde, listeden ilk çıkan oluyor. Bu yapıya da denir FIFO(İlk giren ilk çıkar).

    Ekleme ve silme işlemlerine ne dersiniz?

    Q = def ekleme (elem): q.append (elem) # kuyruğun sonuna bir öğe ekle yazdır q def sil (): q.pop (0) # kuyruktan sıfır öğesini kaldır yazdır q

    Yığın

    Böylesine eğlenceli bir hokey oyunundan sonra Loopy herkes için krep yapar. Onları bir yığına koyar.

    Tüm krepler hazır olduğunda Loopy onları tek tek tüm aileye servis eder.

    Yaptığı ilk krepin en son servis edileceğini unutmayın. denir Yığın... Listeye eklenen son öğe ilk ayrılan olacaktır. Ayrıca bu veri yapısı denir hayat(Son Giren İlk Çıkar).

    Öğe ekleme ve kaldırma?

    S = def push (elem): # Yığına bir öğe ekleyin - Push s.append (elem) print s def customPop (): # yığından bir öğeyi kaldırın - Pop s.pop (len (s) -1) baskı s

    Yığın

    Hiç Yoğunluk Kulesi'ni gördünüz mü?

    Yukarıdan aşağıya tüm elemanlar yoğunluklarına göre yerlerine yerleştirilmiştir. İçine yeni bir nesne düşürürseniz ne olur?

    Yoğunluğuna göre gerçekleşecektir.

    Bu nasıl çalışır Yığın.

    Yığın ikili bir ağaçtır. Bu, her ebeveynin iki çocuğu olduğu anlamına gelir. Ve bu veri yapısına yığın desek de, düzenli bir dizi olarak ifade edilir.
    Ayrıca yığın her zaman logn yüksektir, burada n eleman sayısıdır

    Şekil, aşağıdaki kurala dayalı bir maksimum yığını göstermektedir: çocuklar daha küçük ebeveyn. Çocukların her zaman olduğu küçük yığınlar da vardır. daha fazla ebeveyn.

    Yığınlarla çalışmak için birkaç basit işlev:

    Global heap global currSize def parent (i): # i-th öğesinin üst dizinini al return i / 2 def left (i): # i-th öğesinin sol çocuğunu get return 2 * i def right (i ): # i-inci dönüşün sağ çocuğunu alın (2 * i + 1)

    Mevcut bir yığına öğe ekleme
    İlk olarak, öğeyi yığının en altına ekliyoruz, yani. dizinin sonuna. Ardından, yerine oturana kadar ebeveynle değiştiririz.

    algoritma:

    1. Öğeyi yığının en altına ekleyin.
    2. Eklenen öğeyi üst öğeyle karşılaştırın; sipariş doğruysa, dururuz.
    3. Değilse, öğeleri değiştiririz ve önceki noktaya döneriz.
    Kod:

    Def takas (a, b): # a indeksli elemanı b indeksli elemanla değiştir temp = yığın [a] yığın [a] = yığın [b] yığın [b] = geçici def ekleme (elem): global currSize index = len (yığın) heap.append (elem) currSize + = 1 par = parent (index) flag = 0 while flag! = 1: if index == 1: # Kök elemana ulaşıldı flag = 1 elif yığın> elem: # Kök elemanın indeksi, elemanımızın indeksinden büyükse - elemanımız yerindedir flag = 1 else: # Ana elemanı takas (par, indeks) ile değiştirin indeks = par par = ebeveyn (index) print yığın
    while döngüsünün maksimum geçiş sayısı ağacın yüksekliğine veya logn'a eşittir, bu nedenle algoritmanın karmaşıklığı O'dur (logn).

    Maksimum Yığın Öğesini Alma
    Yığındaki ilk öğe her zaman maksimumdur, bu yüzden onu sileriz (önceden hatırlayın) ve en düşük olanla değiştiririz. Ardından, bir işlev kullanarak yığını doğru sıraya koyacağız:

    MaxHeapify ().

    algoritma:

    1. Kök elemanı en düşük olanla değiştirin.
    2. Yeni kök öğeyi çocuklarla karşılaştırın. Doğru sıradaysa, durun.
    3. Değilse, kök öğeyi alt öğelerden biriyle değiştirin (min-yığın için daha küçük, max-yığın için daha büyük) ve 2. adımı tekrarlayın.

    Def ExtractMax (): global currSize eğer currSize! = 0: maxElem = yığın yığın = yığın # Kök öğeyi en sonuncusu ile değiştirin heap.pop (currSize) # Son öğeyi kaldırın currSize - = 1 # Yığın boyutunu küçült maxHeapify ( 1) return maxElem def maxHeapify (indeks): global currSize lar = indeks l = sol (indeks) r = sağ (indeks) # Hangi çocuğun daha büyük olduğunu hesaplayın; ebeveynden daha büyükse, l ise değiştirin<= currSize and heap[l] >yığın: lar = l ise r<= currSize and heap[r] >yığın: lar = r ise lar! = dizin: takas (indeks, lar) maxHeapify (lar)
    Ve yine, maxHeapify işlevine yapılan maksimum çağrı sayısı ağaç yüksekliğine veya logn'a eşittir; bu, algoritmanın karmaşıklığının O (logn) olduğu anlamına gelir.

    Herhangi bir rastgele diziden bir demet yapmak
    Tamam, bunu yapmanın iki yolu var. Birincisi, her bir elemanı yığına birer birer yerleştirmektir. Bu basit, ama tamamen etkisiz. Bu durumda algoritmanın karmaşıklığı O (nlogn) olacaktır, çünkü O (logn) işlevi n kez çalışacaktır.

    Daha verimli bir yol, maxHeapify işlevini kullanmaktır. alt yığınlar', From (currSize / 2) ilk öğeye.

    Karmaşıklık O(n) olacaktır ve bu ifadenin ispatı ne yazık ki bu makalenin kapsamı dışındadır. Yığının currSize / 2 to currSize kısmındaki öğelerin çocukları olmadığını ve bu şekilde oluşturulan 'alt yığınların' çoğunun oturum yüksekliğinden daha az olacağını anlayın.

    Def buildHeap(): aralıktaki i için global currSize (currSize / 2, 0, -1): # range () içindeki üçüncü argüman yineleme adımıdır, bu durumda yönü belirler. yığın yazdır maxHeapify (i) currSize = len (yığın) -1

    Gerçekten, tüm bunlar neden?

    Garip bir şekilde, “olarak adlandırılan özel bir sıralama türünü uygulamak için yığınlara ihtiyaç vardır. yığın sıralama”. Korkunç O (n 2) karmaşıklığına sahip daha az verimli "insert sort" ve "balon sort" un aksine, "yığın sıralama" O (nlogn) karmaşıklığına sahiptir.

    Uygulama son derece basittir. Yığından sırayla maksimum (kök) öğeyi almaya devam edin ve yığın boşalana kadar diziye yazın.

    Def heapSort (): i aralığında (1, len (yığın)): yığın yazdır heap.insert (len (yığın) -i, extractMax ()) # maksimum öğeyi dizinin sonuna ekle currSize = len ( yığın) -1
    Yukarıdakilerin hepsini özetlemek için, yığınla çalışmak için işlevleri içeren birkaç satır kod yazdım ve OOP hayranları için her şeyi bir sınıf biçiminde tasarladım.

    Kolay, değil mi? Ve işte kutlayan Lupi!

    Doğramak

    Loopy, çocuklarına şekilleri ve renkleri ayırt etmeyi öğretmek istiyor. Bunu yapmak için eve çok sayıda çok renkli figür getirdi.

    Bir süre sonra, kaplumbağaların kafası nihayet karıştı.

    Bu yüzden işleri biraz daha kolaylaştırmak için başka bir oyuncak çıkardı.

    Çok daha kolay oldu çünkü kaplumbağalar şekillerin şekle göre sıralandığını zaten biliyorlardı. Her gönderiyi işaretlersek ne olur?

    Kaplumbağaların artık belirli bir sayıya sahip bir sütunu kontrol etmeleri ve ihtiyaç duydukları çok daha az sayıda figür arasından seçim yapmaları gerekiyor. Ve her şekil ve renk kombinasyonu için ayrı bir sütunumuz varsa?

    Diyelim ki posta numarası aşağıdaki gibi hesaplanıyor:

    Ad Soyad yaz mevsimi tre Meydan
    ph + u + o + t + p + e = 22 + 10 + 16 + 20 + 18 + 6 = Sütun 92

    Kra uykulu Düz dağ
    k + p + a + n + p + i = 12 + 18 + 1 + 17 + 18 + 33 = Sütun 99

    6 * 33 = 198 olası kombinasyon olduğunu biliyoruz, bu da 198 sütuna ihtiyacımız olduğu anlamına geliyor.

    Sütun sayısını hesaplamak için bu formülü arayalım - Özet fonksiyonu.

    Kod:
    def hashFunc (parça): sözcükler = parça.split ("") # dizeyi sözcüklere böl color = sözcükler şekil = sözcükler poleNum = 0 aralığında i için (0, 3): poleNum + = ord (renk [i]) - 96 poleNum + = ord (şekil [i]) - 96 dönüş poleNum
    (Kiril biraz daha karmaşık, ama basit olması için bu şekilde bıraktım. - yaklaşık)

    Şimdi, pembe karenin nerede saklandığını bulmamız gerekirse, şunu hesaplayabiliriz:
    hashFunc ("pembe kare")

    Bu, öğelerin konumunun bir özet işlevi tarafından belirlendiği bir özet tablosu örneğidir.
    Bu yaklaşımla, herhangi bir elemanı aramak için harcanan zaman, eleman sayısına bağlı değildir, yani. O (1). Yani hash tablosundaki arama süresi sabit bir değerdir.

    Tamam ama diyelim ki arıyoruz” araba güzel Düz moangle "(tabii ki, renk" karamel "varsa).

    HashFunc ("karamel dikdörtgen")
    bize kırmızı dikdörtgenin sayısıyla aynı olan 99'u döndürür. " denir Çarpışma”. Çarpışmaları çözmek için “ zincirleme yöntemi”, Her sütunun ihtiyacımız olan kaydı aradığımız bir liste içerdiğini ima etmek.

    Yani karamel dikdörtgeni kırmızı olanın üzerine koyuyoruz ve hash fonksiyonu o sütunu gösterdiğinde bunlardan birini seçiyoruz.

    İyi bir hash tablosunun anahtarı, doğru hash fonksiyonunu seçmektir. Bu, bir hash tablosu oluşturmada yadsınamaz bir şekilde en önemli şeydir ve insanlar, kaliteli hash fonksiyonları geliştirmek için muazzam miktarda zaman harcarlar.
    İyi tablolarda hiçbir pozisyon 2-3'ten fazla eleman içermez, aksi takdirde hashleme kötü çalışır ve hash fonksiyonunu değiştirmeniz gerekir.

    Bir kez daha, öğeden bağımsız bir arama! Devasa olan her şey için hash tablolarını kullanabiliriz.

    Hash tabloları, algoritmayı kullanarak büyük metin parçalarındaki dizeleri ve alt dizeleri bulmak için de kullanılır. Rabin-Karp veya algoritma Knut-Morris-Pratt, örneğin bilimsel makalelerdeki intihalleri tespit etmek için yararlıdır.

    Bu konuda, bence, bitirebiliriz. Gelecekte, örneğin daha karmaşık veri yapılarına bakmayı planlıyorum. Fibonacci yığını ve segment ağacı... Umarım bu resmi olmayan rehber ilginç ve faydalı olmuştur.

    Kilitli Habr için çevrildi