Почему мы используем массивы вместо других структур данных?

Неустранимая ошибка: Невозможно переопределить класс [имя класса]

Неустранимая ошибка: невозможно обновить [имя функции]

Это означает, что вы либо используете одно и то же имя функции / класса дважды, и вам нужно переименовать один из них, или это потому, что вы использовали require или include, где вы должны использовать require_once или include_once.

Когда класс или функция объявляется в PHP, он неизменен и не может быть позже объявлен с новым значением.

Рассмотрим следующий код:

class.php

<?php

class MyClass
{
    public function doSomething()
    {
        // do stuff here
    }
}

index.php

<?php

function do_stuff()
{
   require 'class.php';
   $obj = new MyClass;
   $obj->doSomething();
}

do_stuff();
do_stuff();

Второй вызов do_stuff() приведет к получению ошибка выше. Изменяя require на require_once, мы можем быть уверены, что файл, содержащий определение MyClass, будет загружен только один раз, и ошибка будет устранена.

192
задан 18 revs, 11 users 54% 30 August 2012 в 08:29
поделиться

3 ответа

Время для возвращения как раз к уроку. В то время как мы не думаем об этих вещах очень на управляемых языках нашего воображения сегодня, они основаны на той же основе, поэтому давайте посмотрим на то, как памятью управляют в C.

, Прежде чем я погружусь в, быстрое объяснение того, что означает термин "указатель". Указатель является просто переменной, которая "указывает" на местоположение в памяти. Это не содержит фактическое значение в этой области памяти, это содержит адрес памяти к нему. Думайте о блоке памяти как почтовый ящик. Указатель был бы адресом к тому почтовому ящику.

В C, массив является просто указателем со смещением, смещение определяет как далеко в памяти для взгляда. Это обеспечивает O (1) время доступа.

  MyArray   [5]
     ^       ^
  Pointer  Offset

Все другие структуры данных или полагаются на это или не используют смежную память для устройства хранения данных, приводящий к плохому произвольному доступу ищут время (Хотя существуют другие преимущества для не использования последовательной памяти).

, Например, скажем, у нас есть массив с 6 числами (6,4,2,3,1,5) в нем в памяти, это было бы похоже на это:

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

В массиве, мы знаем, что каждый элемент друг рядом с другом в памяти. Массив C (Названный MyArray здесь) является просто указателем на первый элемент:

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

, Если бы мы хотели искать MyArray[4], внутренне к нему получили бы доступ как это:

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

, поскольку мы можем непосредственно получить доступ к любому элементу в массиве путем добавления смещения к указателю, мы можем искать любой элемент за то же количество времени, независимо от размера массива. Это означает, что получение MyArray[1000] заняло бы то же количество времени как получение MyArray[5].

альтернативная структура данных является связанным списком. Это - линейный список указателей, каждый указывающий на следующий узел

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

P(X) stands for Pointer to next node.

Примечание, что я сделал каждый "узел" в его собственный блок. Это вызвано тем, что они, как гарантируют, не будут (и скорее всего не будет), смежный в памяти.

, Если я хочу получить доступ к P3, я не могу непосредственно получить доступ к нему, потому что я не знаю, где это находится в памяти. Все, что я знаю, - то, где корень (P1), так вместо этого я должен запустить в P1 и следовать за каждым указателем на желаемый узел.

Это - O (N), ищут время (Взгляд увеличения стоимости, поскольку каждый элемент добавляется). Намного более дорого добраться до P1000 по сравнению с получением к P4.

Высокоуровневые структуры данных, такие как хеш-таблицы, стеки и очереди, все могут использовать массив (или несколько массивов) внутренне, в то время как Связанные списки и Двоичные деревья обычно используют узлы и указатели.

Вы могли бы задаться вопросом, почему любой будет использовать структуру данных, которая требует, чтобы линейный обход искал значение вместо того, чтобы просто использовать массив, но у них есть свое использование.

Берут наш массив снова. На этот раз я хочу найти элемент массива, который содержит значение '5'.

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

В этой ситуации, я не знаю то, что смещает для добавления к указателю для нахождения его, таким образом, я должен запустить в 0, и прокладывать себе путь вплоть до, я нахожу его. Это означает, что я должен выполнить 6 проверок.

из-за этого, ища значение в массиве считается O (N). Стоимость поиска увеличений как массив становится больше.

Помнят выше, где я сказал, что иногда использование не последовательной структуры данных может иметь преимущества? Поиск данных является одним из этих преимуществ, и одним из лучших примеров является Двоичное дерево.

Двоичное дерево А является структурой данных, подобной связанному списку, однако вместо того, чтобы связаться с единственным узлом, каждый узел может связаться с двумя дочерними узлами.

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

 Assume that each connector is really a Pointer

, Когда данные вставляются в двоичное дерево, они используют несколько правил решить, куда поместить новый узел. Фундаментальное понятие - то, что, если новое значение больше, чем родители, оно вставляет его налево, если это ниже, оно вставляет его направо.

Это означает, что значения в двоичном дереве могли быть похожими на это:

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

При поиске двоичного дерева значение 75, мы только должны посетить 3 узла (O (зарегистрируйте N)) из-за этой структуры:

  • 75 меньше чем 100? Взгляд на Правильный Узел
  • Равняется 75 больше, чем 50? Взгляд на Левый Узел
  • существует 75!

Даже при том, что существует 5 узлов в нашем дереве, мы не должны были смотреть на оставление два, потому что мы знали, что они (и их дети) не могли возможно содержать значение, которое мы искали. Это дает нам время поиска, когда в худшем случае случай означает, что мы должны посетить каждый узел, но в лучшем случае мы только должны посетить небольшую часть узлов.

Это - то, где массивы разбиты, они обеспечивают линейный O (N) время поиска, несмотря на O (1) время доступа.

Это - невероятно обзор высокого уровня структур данных в памяти, перескакивая через большое количество деталей, но надо надеяться она иллюстрирует достоинство и недостаток массива по сравнению с другими структурами данных.

767
ответ дан 30 revs, 15 users 89% 23 November 2019 в 05:28
поделиться

Для O (1) произвольный доступ, который не может быть разбит.

73
ответ дан jason 23 November 2019 в 05:28
поделиться

Не все программы делают то же самое или работают на тех же аппаратных средствах.

Это обычно - ответ, почему существуют различные функции языка. Массивы являются базовым понятием информатики. Замена массивов с lists/matrices/vectors/whatever совершенствовалась, структура данных сильно повлияет на производительность и будет совершенно невыполнима во многих системах. Существует любое количество случаев, где использование одного из этих "усовершенствованных" объектов сбора данных должно использоваться из-за рассматриваемой программы.

В программировании бизнеса (который большинство из нас делает), мы можем быть нацелены на аппаратные средства, которые относительно мощны. Используя Список в C# или Вектор в Java правильный выбор сделать в этих ситуациях, потому что эти структуры позволяют разработчику выполнять цели быстрее, который в свою очередь позволяет этому типу программного обеспечения быть более известным.

При записи встроенному программному обеспечению или операционной системе массив может часто быть лучшим выбором. В то время как массив предлагает меньше функциональности, он поднимает меньше RAM, и компилятор может оптимизировать код более эффективно для поисков в массивы.

я уверен, что не учитываю много преимуществ для этих случаев, но я надеюсь, что Вы понимаете.

22
ответ дан 2 revs 23 November 2019 в 05:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: