Neden sıfır tabanlı diziler normdur?


112

Burada sorulan bir soru, bana bir programcı arkadaşımla yaptığım tartışmayı hatırlattı. Sıfır tabanlı dizilerin tek tabanlı dizilerle değiştirilmesi gerektiğini, çünkü sıfıra dayalı dizilerin dizilerden ve işaretçilerden ve bilgisayar donanım işlerinden kaynaklanan bir uygulama detayı olduğunu, ancak bu tür şeylerin daha üst düzeyde yansıtılmaması gerektiğini savundu. Diller.

Şimdi tartışmada gerçekten iyi değilim, bu yüzden kendimi daha uygun hissettiğinden başka sıfır tabanlı dizilere bağlı kalmak için gerçekten iyi bir neden öneremedim. Neden olduğu sıfır diziler için ortak bir başlangıç noktası?


Bir n eleman dizisinde 'n' elemanı yoktur. Bir n-elemanı dizisinin sadece 0'dan n-1'e kadar olan sayıları vardır. Öyleyse, 1'den başlayan bir diziye sahip olsak daha iyi olmaz mı ve böylece bir n-eleman dizisi aslında dizideki n elemanlarını temsil ediyor.

Bir bayttaki ilk bitin 2 ^ 0 değil 2 ^ 0 olması nedeniyle sıfır tabanlı dizileri seviyorum. Bu bana bazen yardımcı olur :)
e-MEE

Örneğin bu listeye bakarsanız , en.wikipedia.org/wiki/… , bir çok etki alanına özgü dillerin 1'de indekslenmeye başladığını ve cs okulu düşüncesinin çoğunun 0'da olduğunu fark edersiniz. Bu konuda çok aptalca tartışmalar yapıldığını fark edecek, yollarını değiştirmek için ikisinden herhangi birini konuşmaya çalışmak anlamsız olabilir. "1" in savunmasında, dünyadaki çoğu insan bunu kullanıyor. Çoğu programcı "0" kullanır. Çoğu insan programcıları anlamıyor, bu yüzden sizi düşündürüyor ...
Rook

Bu sorunun StackOverflow'tan Programlayıcılara geçtiğine ve daha sonra yapıcı olmadığı için kapalı olduğuna inanamıyorum. Bu aptalca.
paercebal

Yanıtlar:


105

Hiçbirimizin Edsger W. Dijkstra'nın "Neden numaralandırma sıfıra başlamalı" makalesinden daha güçlü bir argüman sağlayabileceğini sanmıyorum .


Bazı istatistikler getirdi ve matematik tarzı kanıtı kullandı. Ama eminim birileri hala tartışabilir. Yine de onaylasam da istemezdim.

6
Dijkstra'nın makalesi stille ilgili, fakat sonra argümanları basitlik ve kullanım kolaylığı ile ilgili ... +1.
paercebal

80

Yetki argümanı

Şey ... Görünüşe göre, en son dilleri de dahil olmak üzere çoğu dil sıfır tabanlı. Bu diller oldukça yetenekli insanlar tarafından yazılmış olduğundan, arkadaşın yanlış olmalı ...

Neden bir

neden 1 sıfırdan daha iyi bir başlangıç ​​indeksi olsun ki? Neden 2 ya da 10 değil? Cevabın kendisi ilginç çünkü fikri savunan insanların düşünce süreci hakkında çok şey gösteriyor.

İlk argüman, çünkü daha doğal olmasıdır 1 genellikle tek kişilik çoğunluğu için, en azından tüm diğerlerinden önce ...

Bir numaralı bir argüman son endeks de dizinin büyüklüğe sahip olması ...

Bu tür argümanlar için genellikle duyduğum nedenlerin "kalitesinden" hala etkilendim ... Ve daha fazlasını hatırlattığımda ...

Neden sıfır değil?

... "Bir-temelli" notasyonlar, fazla olmasa da, yüzyıllarca sıfırın varlığını göz ardı eden batı kültüründen geriye kalkar.

İster inanın ister inanmayın, orijinal gregorian takvimi -3, -2, -1, 1, 2, 3'den gidiyor ... Batı bilimine sağladığı problemi hayal etmeye çalışın (örneğin, 1 Ocak -2'den itibaren kaç yıl) Orjinal Gregoryen takviminden daha fazla görmek için 1 Ocak'a kadar.

Tek tabanlı dizileri saklamak gibidir (peki, bunun için küçültülmüş olacağım ... ^ _ ^ ...), 21. yüzyılda miller ve avlular ...

Neden Sıfır? Çünkü matematik!

İlk (OOops ... Üzgünüm ... tekrar deneyeceğim)

Sıfır , Sıfır hiçbir şey, bir şey bir şey. Bazı dini metinler de, "Başlangıçta hiçbir şey yoktu" ifadesini tutar. Bilgisayarla ilgili bazı tartışmalar, dini tartışmalar kadar yakıcı olabilir, bu yüzden bu nokta göründüğü kadarıyla konu dışı değil ... ^ _ ^

İlk olarak , sıfır tabanlı bir diziyle çalışmak ve sıfırıncı değerini yok saymak, tek tabanlı bir diziyle çalışmaktan daha kolaydır ve sıfırıncı değerini bulmak için dolaşır. Bu sebep, eskisi kadar aptalca, ancak o zaman, tek tabanlı dizilerin lehine olan orijinal argüman da oldukça yanlıştı.

İkincisi , sayılarla uğraşma şansınız yüksek olduğunda, bir veya daha fazla matematikle başa çıkacağınızı ve matematikle uğraşırken, şansların iyi olmadığına ve aptalca hacklerin eski sözleşmelerde dolaşmalarına izin vermediğinizi hatırlayalım. Bir-temelli notasyon matematiği sarstı ve yüzyıllarca tarihlendi ve hatalarımızdan ders alarak geleceğe yönelik bilimlerde (bilgisayar dilleri dahil) önlemek için çaba göstermeliyiz.

Üçüncüsü , bilgisayar dili dizileri donanıma bağlı olarak, bir C tamsayı dizisi atayın ve işaretçiyi 10 indisleri sağa hareket ettirdiğinizde doğal bir [-10 - 10] dizisine sahip olursunuz. Bu donanım için doğal değildir. Ama bu matematik içindir. Elbette, matematik eski olabilir, ama son kontrol ettiğimde dünyadaki çoğu insan olmadığına inanıyordu.

Dört , Daha önce başka bir yerde işaret ettiği gibi, ayrık konum için bile (ya da ayrık değerlere indirgenmiş mesafeler için bile), ilk indeks bir binadaki zemin (sıfırdan başlayarak) gibi azalan geri sayım (3, 2, 1, SIFIR) gibi sıfır olacaktır. !), yer yüksekliği, görüntünün ilk pikseli, sıcaklık (273 K su donma sıcaklığı olarak mutlak sıfır için sıfır Kelvin veya sıfır santigrat derece). Aslında, biriyle başlayan tek şey, " ilk , ikinci , üçüncü , vb." Geleneksel yoludur. beni doğal olarak bir sonraki noktaya götüren yineleme notasyonu ...

Beş aşağıdaki (doğal olarak aşağıdaki noktası önceki ) üst düzey kaplar dizine göre, erişilebilir olmasıdır, ancak ile yineleyicileri , endeks sürece kendi içinde bir değeri vardır. "Üst seviye dil" avukatınızın bundan bahsetmediğine şaşırdım. Dizinin kendisinin önemli olması durumunda, matematikle ilgili bir sorunuz olduğu zamanın yarısını oynayabilirsiniz. Ve böylece, konteynırınızın matematik dostu olmasını ve 1’den başlayarak "işinize yarayan gregorian takvimi" gibi matematik engelli olmamasını ve işe yaraması için haksız kesilmiş korsanlara ihtiyaç duymasını istersiniz.

Sonuç

Program arkadaşınız tarafından verilen argüman yanlıştır, çünkü doğaya göre bulanık olan konuşma dillerini / yazılı dil alışkanlıklarını, bilgisayar dillerine (talimatınızın bulanıklaştırılmasını istemediğiniz) ve yanlış bir donanıma bağlayarak gereksiz yere bağlar. Bu sorunun nedeni, dilleri soyutlamada yükseldikçe, sıfıra dayalı dizinin geçmişte kaldığı konusunda sizi ikna etmeyi umuyor.

Sıfır tabanlı diziler matematikle ilgili nedenlerden dolayı sıfır tabanlıdır. Donanımla ilgili nedenlerden dolayı değil.

Şimdi, eğer bu programcı arkadaşınız için bir sorunsa, yineleyiciler ve foreach döngüleri gibi gerçek yüksek seviyeli yapılarla programlamaya başlamasını sağlayın.


sıfır santigrat derece 273,15K;)

2
(Ben Fizik master diploması var) biliyorum, ama ben ... ^ _ ^ ... benim argümanlar renklendirmek çalıştı mizahi tarafı daha ondalık ile oldu oynarken az noktasını keçe
paercebal

20
Paragraflarınız "Sıfır, Birinci, İkinci, Üçüncü, Dört, Beş" olarak etiketlenir. Tutarlılık için, kardinal sayıları ("Sıfır, Bir, İki, Üç, Dört, Beş") veya sıralı sayıları ("Sıfır, Birinci, İkinci, Üçüncü, Dördüncü, Beşinci") kullanmanız gerekir. :-)
ShreevatsaR

10
Benzer şekilde, hayatımızın ilk yılında, bir yaşında değil, sıfır yaşındayız

3
@Nikita Rybak: Asıl şaşırtıcı olan, sizden önce tüm yorumcuların gördüklerini kaçırmış olmanız. Elbette Bill Lizard'ın cevabı doğru. Bu yüzden ona + 1 oy verdim ve bu yüzden sorunun en iyi cevabı seçildi. Benim cevabım, 1 tabanlı dizilerin arkasındaki yanlış nedenlerle alay etmek ve 1 tabanlı bir dizinin sıkıntıya neden olacağı somut vakalar sunmakla ilgili. Yine de, nedenlerin ironi ile karıştırıldığı düşünüldüğünde bile, "ikna edici olmayan birini" bulduğuna şaşırdım ...
paercebal

47

Yarı açık aralıklar iyi oluşturur. Eğer uğraşıyorsanız 0 <= i < limve nelemanlara göre genişletmek istiyorsanız , yeni elemanlar aralıkta endekslere sahiptir lim <= i < lim + n. Sıfır tabanlı dizileriyle çalışma aritmetik kolaylaştırır zaman bölme veya artarda dizileri veya elemanları sayılabilir . Biri daha basit aritmetik işlemlerin daha az hataya yol açabileceğini umuyor .


Yarı açık aralıklar için +1 - sadece her şeyi kolaylaştırır.
Eclipse

29

Bazı dizi manipülasyon türleri, 1 tabanlı dizilerle çıldırır ancak 0 tabanlı dizilerle daha basit kalır.

Bir noktada sayısal analiz programlaması yaptım. FORTRAN ve C ++ ile yazılmış sıkıştırılmış, seyrek matrisleri işlemek için algoritmalar ile çalışıyordum.

FORTRAN algoritmaları a[i + j + k - 2]C ++ 'a sahipken, a[i + j + k]FORTRAN dizisi 1 tabanlı iken C ++ dizisi 0 tabanlıydı.


Katılıyorum. 1 tabanlı bir diziyi yararlı bulduğum tek an, boş öğe dizini için yer açmak istediğim zamandır. Örneğin, bir nesneler dizim varsa ve dizinlerini tanıtıcı olarak kullanırsam ve boş bir tanıtıcı olmasını istiyorsanız.
Fabio Ceconello

Ben de 1 tabanlı dizinin gereksiz komplikasyonuna ben çarptım, 0 tabanlı diziler sınırlı deneyimlerime göre nadir istisnalarla dizi indekslemesi için her zaman daha net kodlar üretti.

FORTRAN ve C ++ endeksleri, ilgili endeksleri sadece 1 ile dengelenirse, 2 ile nasıl değişir? Ayrıca, neden eksi 2? FORTRAN 1 tabanlıysa, 2 (veya 1) eklemez misiniz?
RexE

@RexE: İşte böyle çalışır ve işte bu yüzden 1 tabanlı dizilerle bu kadar karmaşık.
Jay Bazuzi

@RexE: Düz bir diziyle bir 3d diziyi öykündüğünü varsayalım. Daha sonra, 0 bazında, eleman (0 0 0), düz dizideki eleman 0'a karşılık gelir. OTOH, 1 tabanlıysa, eleman (1 1 1), düz dizideki eleman 1'e karşılık gelir: 1 + 1 + 1-2.

22

Bir dizideki dizin gerçekten bir dizin değil. Bu sadece dizinin başlangıcından olan uzaklıktaki uzaklıktır. İlk eleman dizinin başındadır, yani mesafe yoktur. Bu nedenle ofset 0'dır.


3
Bugünlerde tasarlanan çoğu dil için, bu gerçekten de dilde görünmemesi gereken bir uygulama detayıdır (başka sebepler olması dışında)
Jens Schauder

17

Sebepler sadece tarihsel değil: C ve C ++ hala buralarda ve yaygın olarak kullanılıyor ve pointer aritmetik, dizileri 0 dizininde başlatmak için çok geçerli bir neden.

İşaretçi aritmetik olmayan diğer diller için, ilk öğenin 0 veya 1 dizininde olup olmadığı, başka herhangi bir şeyden çok bir kongredir.
Sorun, ilk elemanı olarak dizin 1'i kullanan dillerin boşlukta olmaması ve genellikle sık sık tahmin ettiğiniz -C ya da C ++ 'da yazılan kütüphanelerle etkileşime girmesidir.

VB ve türetilmiş lezzetleri, dizilerin 0 veya 1'de başlamasıyla acı çekti ve uzun süredir bir sorun kaynağı oldu.

Alt satırda: Dilinizin ne kadar tutarlı olduğu sürece ilk element indeksini düşündüğü önemli değil. Sorun şu ki, 1'i ilk endeks olarak kabul etmek pratikte çalışmayı zorlaştırıyor.


Kabul. Tutarlılık önemlidir ve tamamen düşük seviyeli koddan (C / C ++ dahil) kaçınmanın lüksüne sahip değilseniz, o zaman 1 tabanlı dizilerle çalışmak sadece sorun istiyor.
Shog9

Biz buna rağmen bir soru: Düşük seviyeli kodu hiç platform dışı bir şekilde kullanıyor musunuz? Başka bir deyişle, her zaman bir platformda veya başka bir platformdasınız ve hangisini bilmeniz gerekiyor, değil mi?
Dan Rosenstark

1
VB .NET'i genellikle haksız yere malign olduğunu düşünen biri olarak, dizilerdeki VB .NET uygulamasının korkunç olduğunu söylemeliyim. Farkı böldüler ve daha da kafa karıştırıcı hale getirdiler: Diziler 0'dan başlıyor, fakat Dim a as Dimeger (5) 6 konumlu bir dizi yaratıyor . Gerekçe, fazladan bir pozisyona sahip olmanın, dizinin uzunluğunu aşmaktan kaynaklanan böceklerden daha iyi olduğu görülüyordu. Maalesef bunun üzerine (ve Ve ve Veya Bitsel gibi diğer sorunlar), yine de VB. NET'i kullanmayan birçok VB6 programcısının taleplerine boyun eğdiler.
Kyralessa

1
@Kyralessa: Hayır, gerekçenin, gösterimin karşı-sezgisel ve hataya eğilimli olduğunu iyi bilmelerine rağmen, VB6 (otomatik yükseltme asistanı…) ile geriye dönük uyumluluğa sahip olmasıydı. Öte yandan Andve Orbitsel olarak VB6 ile ilgisi yoktur, VB tipi bir dil için tek mantıklı çözüm budur. Sen do var AndAlsove OrElsesizin mantıksal işlemler için.
Konrad Rudolph

Andve Orbitsel olmanın VB6 ile ilgisi var, çünkü VB6'da bitseldi. Çirkin operatörler AndAlsove OrElsebitsel yapılmalıydı, çünkü bitsel işlemler mantıklı olanlardan çok daha az yaygındır. "Geriye dönük uyumluluk" nedeniyle dilin üzerinde bıraktığı gibi çok çirkin siğil var.
Kyralessa

10

Sıfır tabanlı dizilerin kökleri C ve hatta birleştiricidir. İşaretçi matematiği C ile temelde şöyle çalışır:

  • Bir dizinin her elemanı belirli sayıda bayt kaplar. 32 bit tam sayı (açıkçası) 4 bayttır;
  • Bir dizinin adresi, bundan sonraki eşit büyüklükteki bitişik bloklardaki izleyen elemanlar ile dizinin ilk elemanı tarafından işgal edilir.

Göstermek int a[4]için, 0xFF00 değerinde olduğunu varsayalım , adresler:

  • [0] -> 0xFF00;
  • bir [1] -> 0xFF04;
  • [2] -> 0xFF08;
  • [3] -> 0xFF0C.

Bu nedenle, sıfır tabanlı endekslerle, addres matematiği basittir:

Öğenin adresi = Dizinin adresi + dizin * sizeof (tür)

Aslında C ifadelerinin hepsi eşdeğerdir:

  • a [2];
  • 2 [a]; ve
  • * (A + 2).

Tek tabanlı dizilerde matematik (hiç olmadığı kadar) biraz daha karmaşıktır.

Bu yüzden nedenler büyük ölçüde tarihseldir.


1
Orijinal soru zaten “sıfır tabanlı olma dizilerinin, diziler ve işaretçilerden ve bilgisayar donanım çalışmalarından kaynaklanan bir uygulama detayı olduğunu, ancak bu tür şeylerin daha yüksek dillere yansıtılmaması gerektiğini” belirtiyor.

N tabanlı dizilere izin veren dillerin, genellikle sıfır çalışma zamanı maliyetinde otomatik olarak hesaplanan dizi 'ofsetleri' ile kod oluşturduğundan bahsetmeye değer.
Roddy

8

Sıfır tabanlı dizileri kullanırsanız, dizinin uzunluğu geçerli dizinlerin kümesidir. En azından Peano aritmetiğinin söylediği:

0 = {}
1 = 0 U {0} = {0}
2 = 1 U {1} = {0,1}
3 = 2 U {2} = {0,1,2}
...
n = n-1 U {n-1} = {0,1,2...n-1}

Yani bir anlamda en doğal gösterim.


7

Çünkü C’de diziler ve işaretçiler arasında güçlü bir ilişki vardır.

char* p = "hello";
char q[] = "hello";

assert(p[1] == q[1]);

assert(*p == *q)

* p * ile aynıdır (p + 0)

başlangıç ​​indeksi 1 olması daha sonra başınızı ağrıtır.


5

Bir yığın, 1 tabanlı dizilere göre avantajların bir örneğidir. Bir dizin Verilen i , endeksi i 'nin ana ve olan sol çocuk

PARENT[ i ] = i ÷ 2

LCHILD[ i ] = i × 2

Ancak yalnızca 1 tabanlı diziler için. 0 tabanlı dizileriniz için

PARENT[ i ] = ( i + 1) ÷ 2 - 1

LCHILD[ i ] = ( i + 1) × 2 - 1

Ve sonra, i'nin , aynı zamanda o dizinin alt-dizisinin büyüklüğü olması özelliğine de sahipsiniz (yani, [1, i ] aralığındaki göstergeler ).

Fakat sonunda farketmez, çünkü normalden bir eleman daha ekleyerek ve sıfırı yok sayarak 0 tabanlı bir diziyi 1 tabanlı bir dizi haline getirebilirsiniz. Böylece, uygun olduğunda 1 tabanlı dizilerin avantajlarından yararlanmayı seçebilir ve diğer tüm durumlarda 0 tabanlı dizileri daha temiz aritmetik için tutabilirsiniz.


4

Benim hissim, tamamen keyfi olduğunu. Sıfır veya tek tabanlı dizilerle ilgili özel bir şey yok. Kendimi Visual Basic'ten kurtardığımdan beri (çoğunlukla, Excel'de küçük şeyler yapıyorum) 1 tabanlı dizilerle çalışmadım ve ... aynı. Gerçek şu ki, dizinin üçüncü öğesine ihtiyaç duyuyorsanız, sadece 3 veya 2 olarak adlandırılan bir uygulama detayı. Ancak, dizilerle yaptığınız işlerin% 99'u yalnızca iki mutlak noktayla ilgileniyor: ilk öğe ve sayım veya uzunluk. Yine, ilk öğeye bir yerine sıfır, son öğeye ise say-1 veya sayma denilen bir uygulama detayıdır.

Düzenleme: Yanıt verenlerin bazıları, 1 tabanlı dizilerin en son hatalara daha yatkın olduğunu belirtti. Tecrübelerime göre, şimdi düşünerek, bu doğru. VB'de "ya çalışacak ya da patlayacak çünkü tek başımayım" diye düşündüğümü hatırlıyorum. Java'da asla olmaz. Daha iyi olduğumu düşünmeme rağmen, cevap verenlerin bazıları, 0 seviyeli dizilerin daha düşük seviyeli bir dil ile uğraşmak zorunda olmadığınızda EVEN'in daha güzel aritmetik sonuç verdiğini gösteriyor.


PHP'de, string işlevindeki çoğu arama FALSE döndürülmedi. -1 değil.
jmucchiello

Sayımı, son elemanın indeksi ile karıştırıyorsunuz. Sıfır tabanlı veya bir tabanlı diziler kullanıyor olsanız da, boş bir dizinin sayısı her zaman 0'dır. Tek tabanlı dizilerin avantajı, sayımın son elemanın konumu olmasıdır (ancak bu tek avantajla ilgilidir).

Her iki nokta için de geçerlidir: son yarısı silinmiştir, çünkü sıfır tabanlı veya bir tabanlı diziler için aynıdır: sıfır öğeniz varsa, sayı 0'dır.
Dan Rosenstark

Cevabımın son yarısını kastetmiştim ...
Dan Rosenstark

4

10 + yıl C / C ++ programcısı olarak, Pascal ve Delphi'de çok güçlü bir geçmişe sahip olan Pascal'ın güçlü dizi bağlı ve dizin tipi kontrolünü ve bununla birlikte gelen esnekliği ve güvenliği hala özlüyorum. Bunun açık bir örneği, her ay için değerleri tutan bir dizi verisidir.

Pascal:

 Type Month = (Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec);

  Var Days[Month] of integer;

  ... 
  if Year mod 4 = 0 then // yes this is vastly simplified for leap years and yes i don't know what the comment marker is in pascal and no i won't go look it up
    Days[Feb] := 29
  else
    Days[Feb] := 28;

+/- 1 veya 'sihirli sayılar' kullanmadan benzer dillerde C dillerinde yazmak oldukça zordur. Gün [2] ve Günler [Jan + Dec] gibi ifadelerin derlenmeyeceğini unutmayın; bu, C veya Assembler'da hala düşünen insanlar için acımasız görünebilir.

Pascal / Delphi dillerinin biraz özlemeyeceğim birçok yönü olduğunu söylemeliyim, ancak C sıfır tabanlı diziler kıyaslandığında sadece "aptal" gözüküyor.


Algoritmanızın 2100 yılı için doğru olmadığını belirtmekte fayda var. En.wikipedia.org/wiki/Leap_year#Algorithm

2
Biliyorum ;-) Ancak, bu 2000 yılı için doğruydu. Ben sadece "nokta soyluyu oynuyorum" ...
Roddy

Pedant'ı görün! LOL.
jcollum

Evet. Tüm sayılardan kaçının, istediğiniz diziyi temel alın.
Loren Pechtel

Ortalama Pascal derleyiciniz, makine kodunu oluştururken Jan = 0, Dec = 11 atarsa ​​şaşırmam :-)

4

0'da başlayıp, 1'de başlamamasının nedeni, ofseti dizinin belleğinin başlangıcından bu eleman kadar uzakta düşünebilmenizdir. Bana 0 elementini vermek demek değil - baştan 0 element olan elementi bana söylüyor.

Buna bakmanın başka bir yolu da bunların (çoğunlukla) eşdeğer olmasıdır:

array[n]

*(array + n)

Standardın hiç değişmemesinin nedeni, C'nin yaklaşık 40 yıldan beri var olmasıdır. Bunu değiştirmek için zorlayıcı bir sebep yoktur ve eğer öyleyse, dizinin başlangıcına bağlı olan mevcut kodun tümü 0'da olur.


Aslında, C'deki array[n]gibi yeniden yazabilirsiniz n[array]. Bunu yapmak iyi bir fikir değil, kafa karıştırıcı! Ancak yukarıdaki kimliğinden ve ilavenin değişmeli olması nedeniyle yasaldır (en azından C89’a kadar).
Donal Fellows,

Bu, onu yazmak için çılgınca bir yoldur - saklamak zorunda olduğunuz herhangi bir kodda görürseniz büyük bir uyarı işareti olacaktır. Neyse ki ben bunu rastlamadım ... henüz :)
Dennis Munsie

4

Bazı orijinal konum / bağıl konum bilgilerini içeren kod, 0'dan başlayan dizilerle daha temizdir.

Örneğin: Bir vektörü tanımlanmış bir pozisyonda daha büyük bir vektörde kopyalama kodu 1'den başlayan dizilerle başlayan bir acıdır:

function copyAtPos (dest, vect, i):
    for i from 1 -> vect.length do
        dest[pos+i-1] = vect[i]

0 ile başlayan dizilere karşı:

function copyAtPos (dest, vect, i):
    for i from 0 -> vect.length-1 do
        dest[pos+i] = vect[i]

Büyük konvolutions formülü yazmaya başlarsanız, bir zorunluluk haline gelir.


3

Neden 2 veya 3 veya 20 değil? 1 tabanlı dizilere sahip olmak bir şekilde kolay değildir veya sıfır tabanlı dizileri anlamaktan daha kolaydır veya daha kolaydır. 1 tabanlı dizilere geçebilmek için, her programcının dizilerle nasıl çalışılacağını öğrenmesi gerekir.

Ve ayrıca, mevcut dizilerdeki dengelemelerle uğraşırken, daha mantıklı geliyor. Bir diziden 115 bayt okuduysanız, bir sonraki öbeğin 115'te başladığını biliyorsunuzdur. Ve böylece, sonraki bayt her zaman okuduğunuz baytın boyutudur. 1 tabanlı ile her zaman bir tane eklemeniz gerekir.

Ve bazen, "doğru" işaretçi aritmetiği olmayan bir dilde bile dizilerdeki veri parçalarıyla uğraşmanız gerekir. Java'da, hafıza eşlemeli dosyalarda veya tamponlarda verileriniz olabilir. Bu durumda, i bloğunun ebatında olduğunu bilirsiniz * i. 1 tabanlı bir dizinde blok * i + 1 olur.

1 tabanlı endekslemeyle, birçok teknik her yerde + 1'ler gerektirecektir.


Neden 2 veya 3 veya 20 değil? Çünkü 0 ek kimliktir ve 1 çarpımsal kimliktir. En mantıklılar.

3

1 tabanlı dizileri kullanarak, tek boyutlu bir diziyi çok boyutlu bir diziye dönüştürün:

int w = 5, h = 5, d = 5;

int[] a1 = new int[w * h * d], new a2 = int[w,h,d];

for (int z = 1; z <= d; z++)

  for (int y = 1; y <= h; y++)

    for (int x = 1; x <= w; x++)

      a1[x + (y - 1) * w + (z - 1) * h] = a2[x,y,z];

Y ve z dizinlerinizin, diziniz 1 tabanlı olsa bile 0 tabanlı (y - 1, z - 1) olduğunu unutmayın. Bazı durumlarda, 0 tabanlı dizinlerden kaçınamazsınız. Tutarlılık için, neden her zaman 0 tabanlı dizinler kullanmıyorsunuz?


3

Neden dizilerin birinden başlamasını istiyorsun?

Derken a[x][y], derleyici dönüþtürür: a+(x*num_cols+y). Diziler birde başladıysa, bu olur a+(x*num_cols+y-1). Bu, bir dizi öğesine erişmek istediğiniz her defasında ekstra bir aritmetik işlem olacaktır . Neden programları yavaşlatmak istiyorsunuz?


1
aslında, + ((x - 1) * num_cols) + y - 1) olmak zorunda kalacaktı - hem x hem de y, 1'den başlayacaktı.
Dennis Munsie

2

Burada bir uzuv üzerinde adım ve bir tamsayı 'anahtarlı' diziden farklı bir şey önereceğim.

İş arkadaşınızın, her zaman 1'de saymaya başladığımız fiziksel dünyada bir 'kümenin' bire bir eşlemesini oluşturmaya başladığını düşünüyorum. Bunu anlayabilirim, süslü bir şey yapmadığınızda, bazı kodları anlamak kolaydır. Yazılım ile fiziksel dünya arasında 1 ile 1 arasında eşlendiğinde.

Benim önerim

Sakladığınız şey için tamsayı tabanlı dizileri kullanmayın, ancak başka bir sözlük veya anahtar değer çifti kullanın. Bu harita, keyfi bir tamsayıya bağlı olmadığınız için gerçek hayata daha iyi gelir. Bunun yeri var ve yazılım ile fiziksel dünya arasındaki kavramların 1 ila 1 eşleştirilmesinin yararları nedeniyle olabildiğince kullanılmasını tavsiye ederim.

yani kvp['Name Server'] = "ns1.example.com"; (Bu, bir milyon olası örnekten yalnızca biri).

Discaimer

Bu kesinlikle, matematik temelli kavramlarla çalışırken temelde matematik bir bilgisayarın gerçek uygulamasına daha yakın olduğu için işe yaramaz. Kvp setlerini kullanmak burada hiçbir şeye yardımcı olmayacak, aslında işleri berbat edecek ve daha problemli hale getirecek. Bir şeyin kvp veya bir dizi olarak daha iyi çalışabileceği tüm köşe durumlarda düşünmedim.

Son fikir, mantıklı olan sıfır temelli dizileri veya anahtar / değer çiftlerini kullanmaktır, yalnızca bir çekiçiniz olduğunda, her sorunun bir çivi gibi görünmeye başladığını unutmayın ...


2

Şahsen, bir argüman dizi indekslerini ofset olarak görmektir. Bu sadece mantıklı.

Birincisi onun ilk elemanı olduğunu söyleyebilir, ancak ilk elemanın dizinin orijinine göre kayması sıfırdır. Bu nedenle, dizi orijinini almak ve sıfır eklemek ilk öğeyi verecektir.

Böylece hesaplamada, ilk elemanı bulmak için sıfır eklemek, bir tane eklemek ve sonra bir tane çıkarmaktan daha kolaydır.

Bence daha düşük seviyeli şeyler yapan herkes daima üs sırasını düşünüyor. Üstelik daha yüksek seviyeye başlayan veya sıklıkla algoritmik olmayan programlama yapan insanlar, temel bir sistem isteyebilirler. Ya da belki biz sadece geçmiş deneyimlerden önyargılıyız.


Tam olarak - temelde alt seviye dillerden çevrilmiş bir kongre.

2

1-tabanlı endeksler yerine 0-bazlı endeksleri kullanmanın sadece iki (çok) ciddi sebebi, birçok programcının yeniden düşürülmesinden ve geriye dönük uyumluluktan kaçınıyor gibi görünmektedir .

Aldığınız tüm cevaplarda 1 tabanlı endekslere karşı başka ciddi argümanlar görmedim.

Aslında, endeksler doğal olarak 1 tabanlıdır ve işte nedeni budur.

İlk önce şunu sormalıyız: Diziler nereden geldi? Gerçek dünya eşdeğerleri var mı? Cevabım evet: bilgisayar bilimlerinde vektörleri ve matrisi modelleme şeklimiz . Bununla birlikte, Vektörler ve matris, bilgisayar çağından önce 1 tabanlı endeksleri kullanan (ve günümüzde çoğunlukla 1 tabanlı endeksleri kullanan) matematiksel kavramlardır.

Gerçek dünyada, endeksler 1 bazdır.

Thomas'ın dediği gibi, 0 baz indeks kullanan diller aslında endeksleri değil, ofsetleri kullanıyorlar . Ve bu dilleri kullanan geliştiriciler endeksleri değil dengeleri düşünüyor . İşler açıkça belirtilmişse bu sorun olmaz, ancak söylemezler. Ofset kullanan birçok geliştirici hala endekslerden bahsediyor. Ve endeksleri kullanan birçok geliştirici hala C, C ++, C #, ... ofsetlerini kullandığını bilmiyor.

Bu bir ifade sorunu .

(Diskstra'nın makalesi hakkında not - Yukarıda söylediklerimin aynısını yazıyor : matematikçi 1-temelli endeksler kullanıyor . Fakat Diskstra, matematikçilerin bunları kullanmaması gerektiğini çünkü bazı ifadelerin çirkin olacağını düşündü (örn .: 1 <= n <= 0 () Bu konuda doğru olduğundan emin değil - bu istisnai boş dizileri önlemek için böyle bir paradigma kayması yapmak küçük bir sonuç için çok fazla sorun gibi görünüyor ...)


2
Matematikçiler her zaman 1 tabanlı endeksleri kullanmazlar. X0'ın bir dizinin ilk değeri için bolca kullanıldığını gördüm. Hangisinin daha uygun olduğuna bağlıdır.

2

1900'lere atıfta bulunan “20. yüzyıl” da hiç sinirlendi mi? 1 tabanlı dizileri kullanırken her zaman uğraştığınız sıkıcı şeyler için iyi bir benzetmedir.

.Net IO.stream read yöntemi gibi ortak bir dizi görev düşünün:

int Read(byte[] buffer, int offset, int length)

Kendinizi 0 temelli dizilerin daha iyi olduğuna ikna etmek için yapmamızı önereceğim

Her bir indeksleme stilinde, okumayı destekleyen bir BufferedStream sınıfı yazın. 1 tabanlı diziler için Okuma işlevinin tanımını (örneğin, ofset yerine bir alt sınır kullanın) değiştirebilirsiniz. Fantezi bir şeye gerek yok, sadece basitleştirin.

Şimdi, bu uygulamalardan hangisi daha basittir? Hangisinin buraya +1 ve -1 ofsetleri serpildi? Bende böyle düşünmüştüm. Aslında, indeksleme stilinin önemli olmadığı tek durumun bir Dizi gibi bir dizi olmayan bir şey kullanmanız gerektiği zamanları olduğunu savunuyorum.


Kayan nokta ile karıştırıcı tamsayı mantığı kötü bir benzetme.

2

Dizilerin nasıl yapıldığı yüzünden. Birinden başlamaları pek bir anlam ifade etmiyor. Bir dizi, bellekteki temel bir adres, bir boyut ve bir dizindir. Nnth öğesine erişmek için:

base + n * element_size

Öyleyse 0 açıkça ilk dengelemedir.


1

Bunu yapmanın birkaç yolu var:

  • 0 tabanlı dizi dizinleri
  • 1 tabanlı dizi dizinleri
  • 0 veya 1 tabanlı diziler (VB 6.0 gibi ... bu gerçekten korkunç)

Sonuçta, bir dilin 0 veya 1 tabanlı dizi kullanması önemli değil. Ancak bence en iyi seçenek, programcıların çoğunun bu toplantıya alışması basit bir nedenden ötürü 0 tabanlı diziler kullanmak olduğunu ve bunun zaten yazılı kodun büyük çoğunluğuyla tutarlı olduğunu düşünüyorum.

Gerçekten yanlış gidebilmenin tek yolu, Visual Basic gibi tutarsız olmak. Şu anda bakımını yaptığım kod tabanı, 0 ile 1 tabanlı diziler arasında bölünmüş durumda; hangisinin hangisi olduğunu bulmak oldukça zor. Bu döngü için can sıkıcı bir fiil yol açar:

dim i as integer, lb as integer, ub as integer
lb = LBound(array)
ub = UBound(array)
for i = lb to ub
       '...
next

hahaha hatırlıyorum, emilen adam ...
Dan Rosenstark

Negatif sayılarla başlayan dizileri bile hatırladığımı düşünüyorum. VB'den uzak durmamın birçok nedeninden sadece biri.

1

Sıfır, bir öğenin doğrusal bir koleksiyondaki yeri hakkında konuşurken doğaldır .

Kitaplarla dolu bir raf düşünün - ilk kitap rafın yan duvarı ile aynı hizada bulunur - bu konum sıfırdır.

Bu yüzden, dizi indekslerini bir şeyleri bulmak için mi yoksa bir şeylere atıfta bulunmak için mi kullandığınıza bağlı olduğunu düşünüyorum.


1

Modulo (ve modulo için kullanıldığında AND işleci) bazı değerler için her zaman 0 döndürdüğünden 0 tabanlı dizin tercih ediyorum.

Sık sık kendimi böyle diziler kullanarak buluyorum:

int blah = array[i & 0xff];

1 temelli indeks kullanırken bu tür kodları sıklıkla yanlış anladım.


1

Dize arama ve çeşitli sıralama / birleştirme algoritmaları ya da tek boyutlu bir dizide çok boyutlu dizileri simüle etme gibi çok sayıda dizi tabanlı kod programlamadan 0 temelini savunmak zordur. Fortran 1 tabanlı ve bu tür kodları doğru bir şekilde yapabilmek için çok fazla kahveye ihtiyacınız var.

Ama bunun ötesine geçiyor. Öğelerinin endekslerinden ziyade bir şeyin uzunluğunu düşünebilmek çok yararlı bir zihinsel alışkanlıktır. Örneğin, piksel tabanlı grafikler yaparken, koordinatları kendinden ziyade piksellerin arasına düşen olarak düşünmek daha açıktır. Bu şekilde 3x3 bir dikdörtgen 16 değil 9 piksel içerir.

Biraz daha uzak bir örnek, ayrıştırmada ileriye bakma veya bir tablonun alt toplamlarını yazdırma fikridir. "Sağduyu" yaklaşımı 1) bir sonraki karakteri, jetonu veya masa sırasını almak ve 2) onunla ne yapacağına karar vermek. İleriye dönük yaklaşım, 1) görebildiğinizi varsayalım ve isteyip istemediğinize karar verir ve 2) isterseniz, "kabul et", (bir sonrakini görmenizi sağlar). Sonra sözde kodu yazarsanız, çok daha basittir.

Yine bir başka örnek, "goto" yu MS-DOS toplu iş dosyaları gibi başka seçeneğiniz olmayan dillerde kullanmaktır. "Sağduyulu" yaklaşım, yapılacak kod bloklarına etiketler eklemektir ve bu şekilde etiketlemektir. Genellikle daha iyi bir yaklaşım, etiketlerin üstünden atlamak amacıyla kod bloklarının sonuna koymaktır. Bu "yapılandırılmış" ve değiştirmesi çok daha kolay hale getirir.


1

Bu sadece öyle ve uzun yıllar oldu. Değiştirmek, hatta tartışmak bile, değişen trafik ışıklarını değiştirmek veya tartışmak kadar anlamsız. Mavi yapalım = duralım, kırmızı = gidelim.

C ++ için Sayısal Tarifler içinde zaman içinde yapılan değişikliklere bakın. 1 tabanlı indeksleme yapmak için makro kullanıyorlardı, ancak 2001'de bıraktı ve sürüye katıldı. Bunun arkasındaki nedenlerle aydınlatıcı materyaller www.nr.com adresinde bulunabilir.

BTW, ayrıca sinir bozucu bir dizi dışında bir aralık belirtmenin varyantlarıdır. Örnek: python ve IDL; 100 elementi elde etmek için [100: 200] a [100: 199] 'a karşı bir. Sadece her dilin tuhaflıklarını öğrenmelisin. Bir diğeriyle eşleşecek şekilde bir dili değiştirmek, dişlerin bu şekilde sarsılmasına ve gıcırdamasına neden olur ve herhangi bir gerçek sorunu çözmez.


1

0 tabanlı dizileri tercih ederim, çünkü diğerleri tarafından bahsedildiği gibi matematiği kolaylaştırır. Örneğin, bir 10x10 ızgarayı taklit eden 1 boyutlu 100 öğeli bir dizimiz varsa, r, col c satırındaki öğenin dizi dizini nedir:

0 tabanlı: i = 10 * r + c
1 tabanlı: i = 10 * (r - 1) + c

Ve i indeksi göz önüne alındığında satır ve sütuna geri dönelim:

0 tabanlı: c =% 10
         r = kat (i / 10)
1 tabanlı: c = (i - 1)% 10 + 1
         r = tavan (i / 10)

1 tabanlı dizileri kullanırken yukarıdaki matematiğin açıkça daha karmaşık olduğu göz önüne alındığında, standart olarak 0 tabanlı dizilerin seçilmesi mantıklı görünüyor.

Bununla birlikte, birisinin mantığımın hatalı olduğunu iddia edebileceğini düşünüyorum, çünkü 1B dizisinde 2D verilerini temsil etmek için bir neden olacağını varsayıyorum. C / C ++ 'da bu gibi birkaç durumla karşılaştım, ancak bu tür hesaplamaları yapma ihtiyacının biraz dile bağlı olduğunu kabul etmeliyim. Diziler her zaman istemci için tüm dizin matematiğini gerçekten gerçekleştirdiyse, derleyici derleme zamanında M-tabanlı dizi erişimlerinizi 0-tabanlı hale getirebilir ve bu uygulama detaylarını kullanıcıdan gizleyebilir. Aslında, herhangi bir derleme zamanı sabiti aynı işlemleri yapmak için kullanılabilir, ancak bu tür yapılar muhtemelen anlaşılmaz bir kodla sonuçlanacaktır.

Belki de daha iyi bir argüman, bir dizideki dizi dizini işlem sayısını en aza indirmenin 1 tabanlı dizileri olan bir dilden tavan işlevi kullanılarak gerçekleştirilmesini gerektirmesi olabilir. Bununla birlikte, matematiksel bir bakış açısıyla, tamsayı bölünmesi, d ve r'nin her ikisinin de pozitif olduğu, geri kalanı r'yi geri döndürmelidir. Bu nedenle matematiği basitleştirmek için 0 tabanlı diziler kullanılmalıdır.

Örneğin, N öğeleri içeren bir arama tablosu oluşturuyorsanız, geçerli değerden önce x değerinin dizisine en yakın dizin (yaklaşık olarak sonucun yuvarlamadan önce bir tam sayı olduğu değerleri yok sayarak) olacaktır:

0 tabanlı zemine dayalı: taban ((N - 1) * x / xRange)
1 tabanlı kat: kat ((N - 1) * x / xRange) + 1
1 tabanlı tavan ile: tavan ((N - 1) * x / xRange)

Standart aşağı yuvarlama sözleşmesi kullanılırsa, 1 tabanlı dizilerin istenmeyen bir ek işlem gerektirdiğine dikkat edin. Bu tür bir matematik, derleyici tarafından gizlenemez, çünkü sahne arkasında neler olduğu hakkında daha düşük düzeyde bilgi gerektirir.


Çok boyutlu dizileri destekleyen daha yüksek seviyeli dillere sahip olmanızın iyi bir nedenidir.

1

Bahse girerim, programcı günlük düşünmeye dayanarak 0 tabanlı bir dizinin karşı sezgiselliğine kızmıştı ve dizileri tanımlamanın daha sezgisel bir yolunu savunuyordu. İnsanları "sınıfları" ortaya çıkarmak için çok fazla zaman harcadığımız için kodları gereğince daha açık bir şekilde tanımlayabilmemiz için ironik buluyorum, ancak daha sonra 0 - 1 dizilere bakarken takılıyoruz gibi görünüyor yalnız mantığı.

Bilgisayar söz konusu olduğunda ve matematiksel olarak 0 muhtemelen daha iyi olacak, ama burada bir noktanın kaçırıldığını hissediyorum. Eğer olayları daha insani bir şekilde (örneğin sınıflar) tanımlamak isteseydik, neden dilin diğer bölümleri için de aynı şeyi istemiyoruz? Bir dili insanlar için daha kolay anlaşılabilir ve kullanılabilir hale getirmek için eşit derecede mantıklı ya da geçerli değil (ya da bu konuda daha yüksek önceliğe sahip mi?) kullanılabilir bir yaratımın daha hızlı üretilmesi. PHP Örneği:

array(1 => 'January', 'February', 'March');

isteğimiz başına 1 tabanlı bir dizi verir.

Neden norm olmasın :

array('January', 'February', 'March');

Ve istisna:

array(0 => 'Value for scenario where 0 *has* to be used as the key',
      'value2', 'value3');

PHP söz konusu olduğunda, benim iddiam, gerçek dünya kullanım durumlarında mantık hatalarını azaltacak ya da en azından ortalama olarak daha fazla neden olmayacak şekilde varsayılan sözdizimi açısından 1 tabanlı bir dizinin% 80'idir. Kodlayıcıda daha kolay kullanılabilir kod üretmek için daha kolay. Unutmayın, ihtiyaç duyulduğunda hala dizi (0 => 'değer') seçeneğinin olabileceğini ve aynı zamanda çoğu zaman gerçek bir dünya tanımına daha yakın bir şeyler yapmanın pratik olduğunu varsayarak olduğunu tahmin ediyorum.

Bu, gerçekten bu bakış açısına bakarken bir istek çok fazla gelmiyor. Bir arayüze yaklaşırken, bir programcı için bir işletim sistemi veya dil olsun, insan düşüncesine ve onu tasarladığımız alışkanlıklara, çoğu durumda ne kadar mutlu olursak olacağız ve insan ile bilgisayar arasındaki daha az yanlış anlama var (insan mantığı- böcek)) ve daha hızlı üretim, vb. Eğer gerçek dünyadaki zamanın% 80'i, liste yaparken ya da sayırken 1'i olan şeyleri tarif edersem, bilgisayar anlamımı ideal bir şekilde, az bir bilgi ile anlayabileceği bir şekilde yorumlamalı ya da normal bir şeyi açıklama biçimimden mümkün olduğunca değiştirmelidir. Kısacası gerçek dünyayı ne kadar yakınlaştırabilirsek, soyutlama o kadar iyi kalitede olur. Yani istediği şey hiçbir şekilde aptalca değildir, çünkü nihai amaç budur ve daha fazla soyutlamaya ihtiyaç duyulduğunun kanıtı olacaktır. Bilgisayar hala sonuçta onu 0 tabanlı bir dizinin özel bir kullanımı olarak görebilir. Bilgisayarın, zaman içinde daha az hatayla ne yapmak istediğimi tarif etmem daha basit ve sezgisel bir yol olduğu sürece nasıl yorumlayacağıyla daha az ilgilenebilirim.

Demek iki kuruşum. Ne söylediğinden veya yorumlandığından ne demek istediğinden ciddi olarak şüpheliyim. Muhtemelen kastediyordu, "Bilgisayara istediğimi söylemenin daha az sezgisel bir yolundan nefret ediyorum." :) Hepimiz değil mi? lol.


1

"Kendi" kodunuzu yazarken dikkatli olmanız mümkündür. Dizininizin n> = 0 için n'den başladığını ve buna göre programlandığını varsayabilirsiniz.

Standart olarak, Borealid'in büyük bir tartışması var.

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.