Это не официальный сайт wikipedia.org 01.01.2023

Алгоритм Грэхема — Википедия

Алгоритм Грэхема

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

АлгоритмПравить

В качестве входных данных процедуры Graham выступает множество точек Q, где | Q | 3  . В ней вызывается функция Top(S), которая возвращает точку, находящуюся на вершине стека S, не изменяя при этом его содержимое. Кроме того, используется также функция NextToTop(S), которая возвращает точку, расположенную в стеке S, на одну позицию ниже от верхней точки; стек S при этом не изменяется.

Graham(Q)
1) Пусть 
  
    
      
        
          p
          
            0
          
        
      
    
    
    — точка из множества Q с минимальной координатой y или самая левая из таких точек при наличии совпадений
2) Пусть 
  
    
      
        <
        
          p
          
            1
          
        
        ,
        
          p
          
            2
          
        
        ,
        
        ,
        
          p
          
            m
          
        
        >
      
    
    
    — остальные точки множества Q, отсортированные в порядке возрастания полярного угла,
      измеряемого против часовой стрелки относительно точки 
  
    
      
        
          p
          
            0
          
        
      
    
    
    
     (если полярные углы нескольких точек совпадают, то по расстоянию до точки 
  
    
      
        
          p
          
            0
          
        
      
    
    
   )
3) Push(
  
    
      
        
          p
          
            0
          
        
      
    
    
   ,S)
4) Push(
  
    
      
        
          p
          
            1
          
        
      
    
    
   ,S)
5) for i = 2 to m do
6)     while угол, образованный точками NextToTop(S),Top(S) и 
  
    
      
        
          p
          
            i
          
        
      
    
    
   , образуют не левый поворот
            (при движении по ломаной, образованной этими точками, мы движемся прямо или вправо)
7)       do Pop(S)
8)    Push(
  
    
      
        
          p
          
            i
          
        
      
    
    
   ,S)
9) return S

Для определения, образуют ли три точки a  , b   и c   левый поворот, можно использовать обобщение векторного произведения на двумерное пространство, а именно условие левого поворота будет выглядеть следующим образом: u x v y u y v x 0  , где u = { b x a x , b y a y } , v = { c x b x , c y b y }  

Корректность сканирования по ГрэхемуПравить

Если процедура Graham обрабатывает множество точек Q, где | Q | 3  , то по завершении этой процедуры стек S будет содержать (в направлении снизу вверх) только вершины оболочки CH(Q) в порядке обхода против часовой стрелки.

ДоказательствоПравить

После выполнения строки 2 в нашем распоряжении имеется последовательность точек < p 1 , p 2 , , p m >  . Определим подмножество точек Q i = { p 0 , p 1 , , p i }   при i = 2,3,…,m. Множество точек Q — Q m   образуют те из них, что были удалены из-за того, что их полярный угол относительно точки p0 совпадает с полярным углом некоторой точки из множества Q m  . Эти точки не принадлежат выпуклой оболочке CH(Q), так что CH( Q m  ) = CH(Q). Таким образом, достаточно показать, что по завершении процедуры Graham стек S состоит из вершин оболочки CH( Q m  ) в порядке обхода против часовой стрелки, если эти точки просматриваются в стеке снизу вверх. Заметим, что точно так же, как точки p 0  , p 1  , p m   являются вершинами оболочки CH(Q), точки p 0  , p 1  , p i   являются вершинами оболочки CH( Q i  ).

В доказательстве используется сформулированный ниже инвариант цикла. В начале каждой итерации цикла for в строках 6-9 стек S состоит(снизу вверх) только из вершин оболочки CH( Q i 1  ) в порядке их обхода против часовой стрелки.

Инициализация. При первом выполнении строки 6 инвариант поддерживается, поскольку в этот момент стек S состоит только из вершин Q 2   = Q i 1  , и это множество трех вершин формирует свою собственную выпуклую оболочку. Кроме того, если просматривать точки снизу вверх, то они будут расположены в порядке обхода против часовой стрелки.

Сохранение. При входе в новую итерацию цикла for вверху стека S находится точка p i 1  , помещенная туда в конце предыдущей итерации (или перед первой итерацией, когда i = 3). Пусть p j   — верхняя точка стека S после выполнения строк 7-8 цикла while, но перед тем, как в строке 9 в стек будет помещена точка p i  . Пусть также p k   — точка, расположенная в стеке S непосредственно под точкой p j  . В тот момент, когда точка p j   находится наверху стека S, а точка p i   ещё не добавлена, стек содержит те же точки, что и после j-й итерации цикла for. Поэтому, согласно инварианту цикла, в этот момент стек S содержит только CH( Q j  ) в порядке их обхода против часовой стрелки, если просматривать их снизу вверх. Полярный угол точки p i   относительно точки p 0   больше, чем полярный угол точки p j  , и поскольку угол p k   p j   p i   сворачивает влево(в противном случае точка p j   была бы снята со стека), после добавления в стек S точки p i   (до этого там были только вершины CH( Q j  )) в нем будут содержаться вершины CH( Q j { p i }  ). При этом они будут расположены в порядке обхода против часовой стрелки, если просматривать их снизу вверх.

Покажем, что множество вершин CH( Q j { p i }  ) совпадает с множеством точек CH( Q i  ). Рассмотрим произвольную точку p t  , снятую со стека во время выполнения i-й итерации цикла for, и пусть p r   — точка, расположенная в стеке S непосредственно под точкой p t   перед снятием со стека последней(этой точкой pr может быть точка p j  ). Угол p r   p t   p i   не сворачивает влево, и полярный угол точки p t   относительно точки p 0   больше полярного угла точки p r  . Так как точка p t   находится внутри треугольника, образованного тремя другими точками множества Q i  , она не может быть вершиной CH( Q i  ). Так как p t   не является вершиной CH( Q i  ), то CH( Q i   — { p t  }) = CH( Q i  ). Пусть P i   — множество точек, снятых со стека во время выполнения i-ой итерации цикла for. Верно равенство CH( Q i   — P i  ) = CH( Q i  ). Однако Q i   — P i   = Q i     { p i  }, поэтому мы приходим к заключению, что CH( Q j     { p i  }) = CH( Q i   — P i  ) = CH( Q i  ).

Сразу после вытеснения из стека S точки p i   в нем содержатся только вершины CH( Q i  ) в порядке их обхода против часовой стрелки, если просматривать их в стеке снизу вверх. Последующее увеличение на единицу значения i приведет к сохранению инварианта цикла в очередной итерации.

Завершение. По завершении цикла выполняется равенство i = m + 1, поэтому из инварианта цикла следует, что стек S состоит только из вершин CH( Q m  ), то есть из вершин CH(Q). Эти вершины расположены в порядке обхода против часовой стрелки, если они просматриваются в стеке снизу вверх.

Время работыПравить

Время работы процедуры Graham равно O ( N log N )  , где N = | Q |  . Как несложно показать, циклу while потребуется время O( N  ). В то время, как сортировка полярных углов займет O ( N log N )   времени, откуда и следует общая асимптотика процедуры Graham.

См. такжеПравить

ЛитератураПравить

  • Т. Кормен, Ч. Лейзерсон, Р. Ривест, К. Штайн. Алгоритмы. Построение и анализ = Introduction to Algorithms. — 2-e изд. — “Вильямс”, 2005.

СсылкиПравить