2015-11-22 7 views
0

С массивом, основанным на deque, почему добавляется и удаляется с фронта амунированного O (1)? Мне было бы разумно, что всегда будет O (n), потому что любая операция будет означать, что текущие значения массива должны быть «перемещены» справа от индекса 0 для добавления и перехода влево для удаления ...Array Based Deques: Почему AddFront/RemoveFront O (1)?

Мой профессор говорит, что вам не нужно сменять, просто обновите hi и lo. Я не совсем уверен, что он имеет в виду.

Это не вопрос C++, но я пытаюсь понять его на этом языке.

+0

Я предполагаю, что он просто перемещает указатель на «фронт» и «назад» в разные места в массиве. Это изменяет логическую структуру очереди без фактического перетасовки вокруг всего внутри нее. –

ответ

0

У вас есть 2 указатели (привет и Lo), которые указывают на каждом конце дека :

"aaaaa" <- hi 
"bbbbb" 
"ccccc" 
"ddddd"<- lo 

Затем, когда вы поп с одного конца или другого, вы просто вернуть то, что указатель указывает на и изменить указатель, чтобы указать на следующий/предыдущий:

//"aaaa" is still in the array but not considered part of the deque 
"bbbbb" <- hi 
"ccccc" 
"ddddd" <- lo 

Значительно упрощенный пример:

class Deque { 
int deque[10]; 
int hi, lo; // Initialize in constructor to -1 to flag deque is empty 

public: 
void push_front(int x) { 
    // First time, add to middle of array 
    if (-1 == lo) { 
     hi = lo = 5; // Since array size is 10; 
     deque[5] = x; 
    } 
    // Shift required? 
    else if (lo == 0) { 
     // Check if deque is full 
     if (9 == hi) { 
      // return error or get more space 
     } 
     else { 
      // Shift by one 
      // More optimally you would shift enough to move data to center of array 
      for (int i = hi; i >= lo; --i) { 
       deque[i + 1] = deque[i]; 
      } 
      // Update hi 
      hi += 1; 
      // Store in lo - lo remains at 0 
      deque[0] = x; 
     } 
    } 
    // No shift required 
    else { 
     deque[--lo] = x; 
    } 
} 
// TODO: push_back, pop_front, pop_back 
+0

damnit, я должен был понять, что он использует указатели. хорошо, это имеет смысл сейчас. но если вы добавите на передний план, вам все равно придется перемещать/перемещать предметы? – ohbrobig

+0

Да, сдвиг будет происходить при добавлении, но только когда у вас заканчивается пространство с обоих концов. –

+0

Допустим, вы создали этот deque: {3, 5, 10, 12}, затем сделали пять дополнений. (Не беспокойтесь о размере/пробеле). Не будет ли каждый addfront означать, что вам придется сдвигать, и после каждого addfront lo будет ссылаться на новое значение? – ohbrobig

0

Я не понимаю, точная C реализации ++ дека, но вот моя лучшая попытка рационализировать требования Вашего профессора о временной сложности:

От cppreference и cplusplus, кажется, что двусторонние очереди сохраняются без смежно.

Here - еще один вопрос StackOverflow, который предоставляет полезный образ и некоторую обогащающую информацию.

Обратите внимание, что start просто указывает на фронт, но также возможно иметь unused части отдельных кусков. Поэтому, возможно, нет необходимости перекладывать все, когда выскакивает фронт, если мы можем просто отметить старый фронт как «неиспользованный» и несколько похожий на спину.

EDIT: Я предполагаю, что из-за того, что в начале и конце есть порции unusued, относительно легко добавить к передней или задней части, пока, как сказал Джон в своем собственном ответе, вы исчерпали комнату/«ударить границу».

+0

'std :: deque' должен быть несмежным, поскольку он имеет ограничения на недействительность итератора и т. Д. Это не является строго необходимым для амортизации O (1) вставки с обоих концов. –

+0

Я пытался исследовать то, что вы имели в виду под «недействительностью итератора», поскольку я не знаком с этим термином. Основываясь на том, что я пытался исследовать, я предполагаю, что эти «ограничения» обусловлены характеристиками deque (только для того, чтобы pop/push спереди/назад). Это правда? Кроме того, я не понимаю, почему «ограничения на недействительность итератора» потребуют «несмежного» хранилища. Не могли бы вы объяснить это требование? –

+0

Я ошибался, итераторы могут быть признаны недействительными при вставке, но ссылок нет. Это означает, что каждый элемент должен оставаться в исходном месте памяти, его нельзя перемещать по мере увеличения размера 'deque', поэтому он должен быть несмежным. Сравните с 'vector', где ссылки становятся недействительными всякий раз, когда контейнер меняет размер. См. Http://stackoverflow.com/questions/6438086/iterator-invalidation-rules для правил. –