Her veri türü işaretçilerle düğümlere mi kaynar?


21

Bir dizi veya vektör sadece bir değer dizisidir. Kesinlikle bağlantılı bir liste ile uygulanabilir. Bu sadece bir sonraki düğüme işaret eden bir grup düğümdür.

Yığınlar ve kuyruklar, Giriş CS derslerinde yaygın olarak öğretilen iki soyut veri türüdür. Sınıfta bir yerde, öğrenciler genellikle altta yatan veri yapısı ile bağlantılı bir liste kullanarak yığınlar ve kuyruklar uygulamak zorunda kalırlar, bu da aynı "düğüm koleksiyonu" fikrine geri döndüğümüz anlamına gelir.

Bir Yığın kullanılarak öncelik sıraları oluşturulabilir. Bir yığın, kökte min değeri olan bir ağaç olarak düşünülebilir. BST'ler, AVL, yığınlar da dahil olmak üzere her türlü ağaç, kenarlarla bağlanan düğümlerin bir koleksiyonu olarak düşünülebilir. Bu düğümler, bir düğümün diğerini işaret ettiği yerde birbirine bağlıdır.

Her veri kavramı her zaman sadece diğer uygun düğüme işaret eden düğümlere kadar kaybolabilir gibi görünüyor. Bu doğru mu? Bu kadar basitse, neden ders kitapları verinin sadece işaretçiler içeren bir grup düğüm olduğunu açıklamıyor? Düğümlerden ikili koda nasıl gideriz?


5
Bahsettiğiniz temel veri yapısına "eksilerini" denir; bunlardan istediğiniz herhangi bir veri yapısını oluşturabilirsiniz. Belirli bir ders kitabı yazarının neden eksilerini açıklamayı seçmediğini bilmek istiyorsanız, o yazara neden bu seçimi yaptıklarını sorun. Bir düğüm düzenlemesinin açıklamasından ikili koda gitmeye "derleme" denir ve bir "derleyicinin" görevidir.
Eric Lippert

18
Ayrıca, tüm veri yapılarının bir diziye kaydığını da iddia edebilirsiniz. Sonuçta, hepsi sadece çok büyük bir dizi olan belleğe çıkıyor.
BlueRaja - Danny Pflughoeft

10
dizinlemesini korumak istiyorsanız, bağlantılı listeyi kullanarak bir dizi uygulayamazsınız . O(1)
svick

5
Üzgünüm, ama "düğümler ve işaretçiler" hakkında konuşmak zaten yemeye yenik düştüğün anlamına geliyor. " Tüm Gerçek Programcıların bildiği gibi, tek yararlı veri yapısı Dizi'dir. Dizeler, listeler, yapılar, kümeler - bunların hepsi özel dizilerdir ve programlama dilinizi her türlü bozmadan kolayca işlenebilir. . komplikasyonların "Ref: "Gerçek programcılar dan," Pascal kullanmayan web.mit.edu/humor/Computers/real.programmers
alephzero

3
... ama daha ciddisi, veri yapıları ile ilgili önemli olan şey , onların nasıl uygulandıkları değil , onlarla yapabileceğiniz şeydir . 21. yüzyılda, bunları kendiniz uygulamak sadece bir programlama alıştırmasıdır - ve tembel eğitimciler için, bu tür egzersizlerin notlandırılması kolay olması, öğrencileri en iyi anlamsız ve en kötü şekilde öğrencileri düşünmeye teşvik ederse daha ağır basar. yeniden icat tekerlekler "gerçek dünya programlama yararlı bir faaliyettir.
alephzero

Yanıtlar:


14

Temel olarak, tüm veri yapılarının kaynaştığı şey budur. Bağlantılı veriler. Düğümlerin hepsi yapay - aslında fiziksel olarak mevcut değiller. İkili bölüm bu noktada devreye girer. C ++ 'da birkaç veri yapısı oluşturmalı ve nesnelerinizin belleğe nereden geldiğine bakmalısınız. Verilerin bellekte nasıl düzenlendiğini öğrenmek çok ilginç olabilir.

Pek çok farklı yapının temel nedeni hepsinin bir şeyde uzmanlaşmasıdır. Örneğin, sayfaların bellekten nasıl çekildiği nedeniyle bağlantılı bir liste yerine bir vektör üzerinden yineleme yapmak genellikle daha hızlıdır. Bağlantılı bir liste daha büyük boyutlu türleri saklamak için daha iyidir çünkü vektörler kullanılmayan yuvalar için ekstra alan ayırmalıdır (bu bir vektörün tasarımında gereklidir).

Bir yan not olarak, bakmak isteyebileceğiniz ilginç bir veri yapısı Hash Tablosudur. Tanımladığınız Düğümler ve İşaretçiler sistemini pek takip etmiyor.

TL; DR: Temelde tüm Düğümleri ve İşaretçileri içerir, ancak çok özel kullanımları vardır ve bir şey için daha iyidir ve diğerleri için daha kötüdür.


1
Benim paketlemem, çoğu verinin gerçekten işaretçilerle bir grup düğüm olarak temsil edilebileceğidir. Bununla birlikte, (a) fiziksel düzeyde, olan bu değildir ve (b) kavramsal düzeyde, değerleri bağlantılı bir liste olarak düşünmek, temel verilerin akıl yürütmesi için yararlı değildir. Her şey sadece düşüncemizi basitleştirmek için soyutlamalar, bu yüzden başka biri muhtemelen işe yarayabilse bile bir durum için en iyi soyutlamayı seçebilir.
derekchen14

13

Her veri kavramı her zaman sadece diğer uygun düğüme işaret eden düğümlere kadar kaybolabilir.

Ah canım hayır. Canımı yakıyorsun.

Başka bir yerde (" İkili arama ağacı ve ikili yığın arasındaki fark nedir? ") Açıklamaya çalıştığım gibi , sabit bir veri yapısı için bile bunu anlamak için birkaç seviye vardır.

Bahsettiğiniz öncelik kuyruğu gibi, yalnızca kullanmak istiyorsanız, soyut bir veri türüdür. Ne tür nesneler depoladığını ve ne tür sorular sorabileceğinizi bilerek kullanırsınız. Bu bir çanta dolusu veri yapısıdır. Bir sonraki düzeyde, ünlü uygulaması olan ikili yığın, bir ikili ağaç olarak anlaşılabilir , ancak son seviye, bir dizi olarak uygulanan verimlilik nedenleridir. Düğüm ve işaretçi yok.

Ayrıca, kesinlikle düğümler ve işaretçiler (kenarlar) gibi görünen grafikler için, iki temel temsiliniz vardır, bitişiklik dizisi ve bitişiklik listeleri. Hayal ettiğim tüm işaretçiler değil.

Veri yapılarını gerçekten anlamaya çalışırken, onların iyi noktalarını ve zayıf zayıflıklarını incelemeniz gerekir. Bazen bir temsil verimlilik için bir dizi kullanır (boşluk veya zaman) bazen işaretçiler vardır (esneklik için). Bu , C ++ STL gibi iyi "hazır" uygulamalarınız olsa bile geçerlidir , çünkü orada da bazen temel gösterimleri seçebilirsiniz. Orada her zaman bir değiş tokuş vardır.


10

f:R,R,

Kimse sizden bunları sürekli bir işlev tanımlamak için söylemenizi beklemez, aksi takdirde hiç kimse hiçbir iş yapamaz. Sadece birisinin bizim için sıkıcı bir iş yaptığına "güveniyoruz".

Düşündüğünüz her veri yapısı, temeldeki hesaplama modelinizin ele aldığı temel nesnelere, rasgele erişimli bir makine kullanıyorsanız bazı kayıtlarda tamsayılara veya Turing makinesi kullanıyorsanız bazı bantlardaki sembollere kaynar.

Soyutlamaları kullanıyoruz çünkü zihnimizi önemsiz konulardan kurtararak daha karmaşık problemler hakkında konuşmamıza izin veriyorlar. Bu yapıların işe yaradığına "güvenmek" son derece mantıklıdır: her ayrıntıya inmek - bunu yapmak için özel bir nedeniniz yoksa - argümanınıza hiçbir şey katmayan nafile bir alıştırmadır.


10

İşte bir karşı örnek: λ hesabında, her veri türü işlevlere kaynar. λ-hesabında düğümler veya işaretçiler yoktur, sahip olduğu tek şey işlevlerdir, bu nedenle her şey işlevler kullanılarak uygulanmalıdır.

Bu, booleları ECMAScript'te yazılmış işlevler olarak kodlamaya bir örnektir:

const T   = (thn, _  ) => thn,
      F   = (_  , els) => els,
      or  = (a  , b  ) => a(a, b),
      and = (a  , b  ) => a(b, a),
      not = a          => a(F, T),
      xor = (a  , b  ) => a(not(b), b),
      iff = (cnd, thn, els) => cnd(thn, els)();

Ve bu bir eksiler listesi:

const cons = (hd, tl) => which => which(hd, tl),
      first  = list => list(T),
      rest   = list => list(F);

Doğal sayılar yineleyici işlevi olarak uygulanabilir.

Bir küme, karakteristik işlevi (yani containsyöntem) ile aynı şeydir .

Yukarıdaki Boolean'ların Kilise Kodlaması'nın, aslında dil yapıları olarak booleans, koşullu veya döngülere sahip olmayan ve yalnızca bir kütüphane özelliği olarak uygulayan Smalltalk gibi OO dillerinde koşulların nasıl uygulandığına dikkat edin. Scala'da bir örnek:

sealed abstract trait Boolean {
  def apply[T, U <: T, V <: T](thn: => U)(els: => V): T
  def(other: => Boolean): Boolean
  def(other: => Boolean): Boolean
  val ¬ : Boolean

  final val unary_! = ¬
  final def &(other: => Boolean) =(other)
  final def |(other: => Boolean) =(other)
}

case object True extends Boolean {
  override def apply[T, U <: T, V <: T](thn: => U)(els: => V): U = thn
  override def(other: => Boolean) = other
  override def(other: => Boolean): this.type = this
  override final val ¬ = False
}

case object False extends Boolean {
  override def apply[T, U <: T, V <: T](thn: => U)(els: => V): V = els
  override def(other: => Boolean): this.type = this
  override def(other: => Boolean) = other
  override final val ¬ = True
}

object BooleanExtension {
  import scala.language.implicitConversions
  implicit def boolean2Boolean(b: => scala.Boolean) = if (b) True else False
}

import BooleanExtension._

(2 < 3) { println("2 is less than 3") } { println("2 is greater than 3") }
// 2 is less than 3

2
@Hamsteriffic: Şunu deneyin: Smalltalk gibi OO dillerinde şartlar bu şekilde uygulanır. Smalltalk, dil yapısı olarak boole, koşul veya döngüye sahip değildir. Bunların hepsi tamamen kütüphane olarak uygulanmaktadır. Zihin hala şişmedi mi? William Cook, uzun zaman önce bariz olması gereken ancak gerçekten fark edilmeyen bir şeye dikkat çekiyor: OO tamamen davranışsal soyutlama ile ilgili olduğundan ve davranışsal soyutlama, λ hesabında var olan tek tür soyutlamadır, λ-hesabı zorunlu olarak OO'dur. Ergo, λ-calculus en eskisidir ve…
Jörg W Mittag

… En saf OO dili!
Jörg W Mittag

1
Smalltalk ile kötü bir gün C ++ ile iyi bir gün atıyor :-)
Bob Jarvis - Monica'yı yeniden eski haline

@ JörgWMittag Sonucunuzun varsayımınızdan geldiğini düşünmüyorum, varsayımınızın bile doğru olduğunu düşünmüyorum ve kesinlikle sonucunuzun doğru olduğunu düşünmüyorum.
Miles Rout

4

Birçok (en çok?) Veri yapısı, düğümler ve işaretçilerden oluşur. Diziler, bazı veri yapılarının bir başka kritik unsurudur.

Nihayetinde, her veri yapısı sadece bir grup sözcük ya da sadece bir parça bittir. Onların nasıl yapılandırıldıkları ve önemli olan onları nasıl yorumladığımız ve kullandığımız.


2
Nihayetinde, bitler bir tel üzerindeki bir grup elektrik sinyali veya bir fiber optik kablodaki ışık sinyalleri veya bir tepside spesifik olarak mıknatıslanmış parçacıklar veya belirli dalga boyunda radyo dalgaları veya veya veya veya. Yani soru şu ki, ne kadar derine gitmek istiyorsunuz? :)
Joker

2

Veri yapılarının uygulanması her zaman düğümlere ve işaretlere kadar kaynar, evet.

Ama neden orada dursun? Düğümlerin ve işaretçilerin uygulanması bitlere kadar kaynar .

Bitlerin uygulanması elektrik sinyallerine, manyetik depolamaya, belki de fiberoptik kablolara, vb.

Bu , "Tüm veri yapıları düğümlere ve göstergelere kadar kaynar" ifadesinin indirgenmesidir . Bu doğrudur - ancak yalnızca uygulama ile ilgilidir .


Makalesi özellikle veritabanlarına yönelik olsa da, Chris Date uygulama ve model arasında çok farklılıklar gösteriyor .

Model ve uygulama arasında tek bir ayrım çizgisi olmadığını fark edersek biraz daha ileri gidebiliriz . Bu (özdeş değilse) "soyutlama katmanları" kavramına benzer.

Belirli bir soyutlama katmanında, sizi "altta" oluşturan katmanlar (üzerinde inşa ettiğiniz katmanlar) , ele aldığınız soyutlama veya model için yalnızca "uygulama ayrıntıları" dır.

Bununla birlikte, soyutlamanın alt katmanlarının kendilerinin uygulama ayrıntıları vardır.

Bir yazılım parçası için bir el kitabı okursanız, kendi yazılımınızı oluşturabileceğiniz (veya yalnızca mesaj gönderme gibi eylemleri gerçekleştirebileceğiniz) yazılım parçası tarafından "sunulan" soyutlama katmanını öğrenirsiniz.

Eğer öğrenirsek uygulama ayrıntılarını yazılımın parçasının, sen yaratıcıları onlar inşa soyutlamalar desteklenen öğreneceksiniz. "Uygulama ayrıntıları", diğer şeylerin yanı sıra veri yapılarını ve algoritmaları içerebilir.

Ancak, olur değil , gerilim ölçüm yazılımı herhangi bir parçası için "uygulama ayrıntıları" parçası olarak görüyoruz bile bu bunun altındaki olsa nasıl "bit" ve "bayt" ve fiziksel bilgisayarda aslında "depolama" çalışması.

Özetle, veri yapıları algoritmalar ve yazılımlar hakkında akıl yürütme ve uygulama için bir soyutlama katmanıdır. Bu soyutlama katmanının, düğümler ve işaretçiler gibi daha düşük düzeydeki uygulama ayrıntıları üzerine inşa edilmiş olması, doğru ancak soyutlama katmanı içinde ilgisizdir .


Bir sistemi gerçekten anlamanın büyük bir kısmı , soyutlama katmanlarının nasıl bir araya geldiğini kavramaktır . Bu nedenle veri yapılarının nasıl uygulandığını anlamak önemlidir . Ama aslında edilir uygulanan, veri yapılarının soyutlama olmadığı anlamına gelmez mevcuttur.


2

Bir dizi veya vektör sadece bir değer dizisidir. Kesinlikle bağlantılı bir liste ile uygulanabilir. Bu sadece bir sonraki düğüme işaret eden bir grup düğümdür.

Bağlantılı bir listeyle bir dizi veya vektör uygulanabilir, ancak neredeyse hiç olmamalıdır.

nnΘ(n)Θ(günlükn)Θ(1)(yani rasgele erişim belleğinin ardışık bir bloğu). Ayrıca, CPU'da, gerçek diziye erişmek çok daha basittir ve yürütülmesi daha hızlıdır ve saklamak, ayrı düğümler arasındaki işaretçiler üzerinde herhangi bir alan boşa harcamaması nedeniyle daha az bellek gerektirir.

Θ(n)Θ(1)Θ(1)ortalama olarak, en fazla sabit bir ekstra bellek faktörü pahasına, sadece dizinin gerçek tahsis edilen boyutunu örneğin 2'nin en yakın gücüne yuvarlayarak. Ama çok fazla ekleme ve / veya kaldırma yapmanız gerekiyorsa listenizdeki öğelerde, fiziksel bir dizi veri yapınız için en iyi uygulama olmayabilir. Yine de, ekleme ve çıkarma işlemlerini ucuz olan takaslarla değiştirebilirsiniz.

Kapsamınızı biraz genişletirseniz, araç kutunuza fiziksel bitişik diziler eklemek için, hemen hemen tüm pratik veri yapıları, düğümler ve işaretçilerle birlikte gerçekten uygulanabilir.

Θ(1)ters işlem). Bununla birlikte, pratikte, bu özellikler, ekstra uygulama karmaşıklığı ve standart çöp toplama şemalarıyla uyumsuzluğu içeren dezavantajlarının üstesinden gelmek için nadiren yararlıdır .


1

Bu kadar basitse, neden ders kitapları verinin sadece işaretçiler içeren bir grup düğüm olduğunu açıklamıyor?

Çünkü "veri" demek değildir. Soyut fikirleri uygulamalarla karıştırıyorsunuz. "Veri" son derece soyut bir fikirdir: "bilgi" için başka bir isimdir. İşaretçilerle bir dizi bağlantılı düğüm (diğer bir deyişle, "bağlantılı veri yapısı") çok daha somut bir fikirdir: Bu, bilgiyi temsil etmenin ve düzenlemenin belirli bir yoludur.

Bazı veri soyutlamaları "bağlantılı" uygulamalara çok iyi borç vermektedir. Tamamen genel bir ağacın dallanma doğasını açık düğümler ve işaretçiler (veya düğümlerin ve işaretçilerin bazı izomorfizmi) kullanmadan uygulamak için pek iyi yol yoktur. Ancak, düğümler ve işaretçiler kullanarak asla uygulayamayacağınız başka soyutlamalar da vardır. Kayan nokta sayıları akla geliyor.

Yığınlar ve kuyruklar arasında bir yere düşer. Bir yığının bağlantılı bir uygulamasını yapmanın çok mantıklı olduğu zamanlar vardır. Bir dizi ve tek bir "yığın işaretçisi" kullanmanın daha anlamlı olduğu başka zamanlar da vardır.

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.