Neden diğer veri yapıları yerine diziler kullanıyoruz?


196

Programlarken, bir dizinin bilgi depolamak için başka bir formdan daha iyi olduğu bir örnek görmedim. Gerçekten de programlama dillerinde eklenen "özellikler" in bunu geliştirdiğini ve onların yerini aldığını anladım. Görüyorum ki, onların yerini almıyorlar, aksine yeni bir hayat veriyorlar.

Temel olarak, dizileri kullanmanın anlamı nedir?

Bu neden dizileri bilgisayar açısından kullanmıyoruz, aksine dizileri programlama açısından neden kullanıyoruz (ince bir fark). Bilgisayarın diziyle yaptığı şey sorunun konusu değildi.


2
Neden bilgisayarın dizi ile ne yaptığını düşünmüyorsunuz? Ev numaralandırma sistemimiz var çünkü STRAIGHT sokaklarımız var. Diziler için de öyle.
lcn

Ne demek " diğer veri yapıları " ya da " başka bir biçim "? Hangi amaçla?
tevemadar

Yanıtlar:


771

Bir ders için zamanda geriye gitme zamanı. Bugün bu şeyleri fantezi yönetilen dillerimizde fazla düşünmese de, bunlar aynı temel üzerine inşa edildi, bu yüzden hafızanın C'de nasıl yönetildiğine bakalım.

Dalış yapmadan önce, " işaretçi " teriminin ne anlama geldiğine dair hızlı bir açıklama . İşaretçi, basitçe bellekteki bir konuma "işaret eden" bir değişkendir. Belleğin bu alanındaki gerçek değeri içermez, belleğin bellek adresini içerir. Bir bellek bloğunu posta kutusu olarak düşünün. İşaretçi, bu posta kutusunun adresi olacaktır.

C de, bir dizi sadece ofseti olan bir göstericidir, ofset bellekte ne kadar görüneceğini belirler. Bu O (1) erişim süresi sağlar.

  MyArray   [5]
     ^       ^
  Pointer  Offset

Diğer tüm veri yapıları bunun üzerine kurulur veya depolama için bitişik belleği kullanmaz, bu da rastgele rasgele erişim arama süresine neden olur (Rağmen sıralı bellek kullanmamanın başka yararları vardır).

Örneğin, içinde 6 rakamlı (6,4,2,3,1,5) bir dizimiz olduğunu varsayalım, bellekte şöyle görünecektir:

=====================================
|  6  |  4  |  2  |  3  |  1  |  5  |
=====================================

Bir dizide, her öğenin bellekte yan yana olduğunu biliyoruz. AC dizisi ( MyArrayburada çağrılır ) sadece ilk öğenin bir göstergesidir:

=====================================
|  6  |  4  |  2  |  3  |  1  |  5  |
=====================================
   ^
MyArray

Eğer bakmak isteseydik MyArray[4], dahili olarak şu şekilde erişilebilirdi:

   0     1     2     3     4 
=====================================
|  6  |  4  |  2  |  3  |  1  |  5  |
=====================================
                           ^
MyArray + 4 ---------------/
(Pointer + Offset)

İşaretçiye ofseti ekleyerek dizideki herhangi bir öğeye doğrudan erişebildiğimiz için, dizinin boyutuna bakılmaksızın herhangi bir öğeyi aynı süre içinde arayabiliriz. Bu, elde etmenin, almakla MyArray[1000]aynı zaman alacağı anlamına gelir MyArray[5].

Alternatif bir veri yapısı bağlantılı bir listedir. Bu, her biri bir sonraki düğüme işaret eden doğrusal bir işaretçiler listesidir

========    ========    ========    ========    ========
| Data |    | Data |    | Data |    | Data |    | Data |
|      | -> |      | -> |      | -> |      | -> |      | 
|  P1  |    |  P2  |    |  P3  |    |  P4  |    |  P5  |        
========    ========    ========    ========    ========

P(X) stands for Pointer to next node.

Her "düğümü" kendi bloğuna yaptığımı unutmayın. Bunun nedeni, bellekte bitişik olmaları garanti edilmemesidir (ve büyük olasılıkla olmayacaklardır).

P3'e erişmek istiyorsam, doğrudan erişemiyorum, çünkü bellekte nerede olduğunu bilmiyorum. Tüm bildiğim kök (P1) nerede, bu yüzden bunun yerine P1 başlamak ve istenen düğüme her işaretçiyi izlemek zorunda.

Bu bir O (N) arama süresidir (Her öğe eklendikçe arama maliyeti artar). P1000'e ulaşmak P4'e kıyasla çok daha pahalı.

Karma tablolar, yığınlar ve kuyruklar gibi daha üst düzey veri yapılarının tümü dahili olarak bir dizi (veya birden çok dizi) kullanabilirken, Bağlantılı Listeler ve İkili Ağaçlar genellikle düğümleri ve işaretçileri kullanır.

Neden herkesin sadece bir dizi kullanmak yerine bir değeri aramak için doğrusal geçiş gerektiren bir veri yapısı kullanacağını merak edebilirsiniz, ancak kullanımları vardır.

Dizimizi tekrar ele alalım. Bu kez, '5' değerini tutan dizi öğesini bulmak istiyorum.

=====================================
|  6  |  4  |  2  |  3  |  1  |  5  |
=====================================
   ^     ^     ^     ^     ^   FOUND!

Bu durumda, işaretçiyi bulmak için hangi ofseti ekleyeceğimi bilmiyorum, bu yüzden 0'dan başlamam ve bulana kadar yukarı doğru çalışmam gerekiyor. Bu 6 kontrol yapmam gerektiği anlamına geliyor.

Bu nedenle, bir dizideki bir değeri aramak O (N) olarak kabul edilir. Dizi büyüdükçe arama maliyeti de artar.

Bazen sıralı olmayan bir veri yapısı kullanmanın avantajları olabileceğini söylediğim yeri hatırlıyor musunuz? Veri aramak bu avantajlardan biridir ve en iyi örneklerden biri de İkili Ağaç'tır.

İkili Ağaç, bağlantılı listeye benzer bir veri yapısıdır, ancak tek bir düğüme bağlanmak yerine her düğüm iki alt düğüme bağlanabilir.

         ==========
         |  Root  |         
         ==========
        /          \ 
  =========       =========
  | Child |       | Child |
  =========       =========
                  /       \
            =========    =========
            | Child |    | Child |
            =========    =========

 Assume that each connector is really a Pointer

Bir ikili ağaca veri eklendiğinde, yeni düğümün nereye yerleştirileceğine karar vermek için birkaç kural kullanır. Temel kavram şudur: eğer yeni değer ebeveynlerden büyükse, onu sola, daha düşükse sağa sokar.

Bu, bir ikili ağaçtaki değerlerin şöyle görünebileceği anlamına gelir:

         ==========
         |   100  |         
         ==========
        /          \ 
  =========       =========
  |  200  |       |   50  |
  =========       =========
                  /       \
            =========    =========
            |   75  |    |   25  |
            =========    =========

75 değeri için bir ikili ağaç ararken, bu yapı nedeniyle sadece 3 düğümü (O (log N)) ziyaret etmemiz gerekir:

  • 75 100'den az mı? Sağ Düğüme Bakın
  • 75 50'den büyük mü? Sol Düğüme Bakın
  • 75 var!

Ağacımızda 5 düğüm olmasına rağmen, kalan ikisine bakmamız gerekmiyordu, çünkü onların (ve çocuklarının) aradığımız değeri içeremeyeceğini biliyorduk. Bu bize en kötü durumda her düğümü ziyaret etmemiz gerektiği anlamına gelen bir arama süresi verir, ancak en iyi durumda düğümlerin sadece küçük bir bölümünü ziyaret etmemiz gerekir.

Dizilerin dövüldüğü yer, O (1) erişim süresine rağmen doğrusal bir O (N) arama süresi sağlar.

Bu, bellekteki veri yapılarına inanılmaz derecede yüksek bir genel bakış, birçok ayrıntıyı atlıyor, ancak umarım bir dizinin diğer veri yapılarına kıyasla gücünü ve zayıflığını gösterir.


1
@Jonathan: Diyagramı 5. öğeye işaret edecek şekilde güncellediniz, ancak MyArray [4] 'ü MyArray [5] olarak değiştirdiniz, bu yüzden hala yanlış, dizini tekrar 4 olarak değiştirin ve diyagramı olduğu gibi tutun ve iyi olmalısınız .
Robert Gamble

54
"Toplum wiki" hakkında beni bu hata ne bu yazı "uygun" temsilcisi değer
Quibblesome

8
Güzel cevap. Ancak tanımladığınız ağaç ikili bir arama ağacıdır - ikili ağaç sadece her düğümün en fazla iki çocuğu olan bir ağaçtır. Öğeleri herhangi bir sırayla içeren bir ikili ağaca sahip olabilirsiniz. İkili arama ağacı, tanımladığınız gibi düzenlenmiştir.
gnud

1
İyi bir açıklama, ama nitpick için yardımcı olamıyorum ... öğeleri bir ikili arama ağacına yeniden sıralamanıza izin verilirse, neden bir ikili arama da çalışacak şekilde dizideki öğeleri yeniden sıralayamıyorsunuz? Bir ağaç için O (n) ekleme / silme, ancak bir dizi için O (n) ile ilgili daha ayrıntılı bilgi verebilirsiniz.
pazarlar

2
Veri kümesinin boyutuna göre erişim süresi logaritmik olarak arttığı için ikili ağaç temsili O (log n) değil mi?
Evan Plaice

73

O (1) dövülemeyen rastgele erişim için.


6
Hangi noktada? O (1) nedir? Rasgele erişim nedir? Neden dövülemiyor? Başka bir nokta?
jason

3
O (1) sabit zaman anlamına gelir, örneğin bir dizinin n-esim elemanını almak istiyorsanız, ona doğrudan dizinleyici (dizi [n-1]) üzerinden erişirsiniz, örneğin bağlantılı bir listeyle, kafayı bulmak ve daha sonra sırayla n-1 kez O (n), doğrusal zaman olan bir sonraki düğüme gitmek için.
CMS

8
Big-O gösterimi, bir algoritmanın hızının girdisinin boyutuna göre nasıl değiştiğini açıklar. Bir O (n) algoritmasının, iki kat daha fazla öğe ile çalıştırılması iki kat daha uzun ve 8 kat daha fazla öğe ile çalıştırılması 8 kat daha uzun sürecektir. Başka bir deyişle, bir O (n) algoritmasının hızı [devam ...] ile değişir
Gareth

8
girdisinin boyutu. O (1), giriş boyutunun ('n') algoritmanın hızını etkilemediğini, giriş boyutundan bağımsız olarak sabit bir hız olduğunu gösterir
Gareth

9
O'nu (1) görüyorum ve seni O (0) olarak yükseltiyorum.
Chris Conway

23

Tüm programlar aynı şeyi yapmaz veya aynı donanımda çalıştırmaz.

Bu genellikle çeşitli dil özelliklerinin varlığının cevabıdır. Diziler temel bir bilgisayar bilimi konseptidir. Dizileri listeler / matrisler / vektörler / her ne olursa olsun gelişmiş veri yapısı ile değiştirmek performansı ciddi şekilde etkiler ve bazı sistemlerde düpedüz uygulanamaz olur. Söz konusu program nedeniyle bu "gelişmiş" veri toplama nesnelerinden birinin kullanılmasının gerektiği çok sayıda durum vardır.

İşletme programlamasında (çoğumuzun yaptığı gibi) nispeten güçlü donanımı hedefleyebiliriz. Bu yapılarda geliştiricinin hedefleri daha hızlı gerçekleştirmesine izin verdiği için C # veya Java'da Vector listelerini kullanmak doğru seçimdir.

Gömülü yazılım veya işletim sistemi yazarken bir dizi genellikle daha iyi bir seçim olabilir. Bir dizi daha az işlevsellik sunmasına rağmen, daha az RAM gerektirir ve derleyici dizilere arama yapmak için kodu daha verimli bir şekilde optimize edebilir.

Eminim bu davalar için birtakım avantajlar bırakıyorum, ama umarım bu konuyu anlarsınız.


4
İronik olarak, Java'da Vector yerine ArrayList (veya LinkedList) kullanmalısınız. Bu, genellikle gereksiz ek yük olan senkronize edilmiş bir vektör ile ilgilidir.
ashirley

0

Dizilerin avantajlarına bakmanın bir yolu, dizilerin O (1) erişim kapasitesinin gerekli olduğunu ve dolayısıyla büyük harflerle yazıldığını görmektir:

  1. Uygulamanızın Arama tablolarında (belirli kategorik yanıtlara erişmek için statik bir dizi)

  2. Bellek (zaten hesaplanmış karmaşık işlev sonuçları, böylece işlev değerini tekrar hesaplamamanız için, x günlüğü diyelim)

  3. Görüntü işleme gerektiren Yüksek Hızlı bilgisayarlı görme uygulamaları ( https://en.wikipedia.org/wiki/Lookup_table#Lookup_tables_in_image_processing )

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.