Программирование на C++

10 способов прострелить себе ногу

Создание веб приложений

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

Подпись для третьего не придумал

Американец изнасиловал лошадь, потому что думал, что у них родится кентавр

Помощь обездоленным якутам на дальнем севере

Благотворительность (на правах рекламы)

Показаны сообщения с ярлыком Сортировки. Показать все сообщения
Показаны сообщения с ярлыком Сортировки. Показать все сообщения

суббота, 5 января 2013 г.

Пирамидальная сортировка (Heapsort) + Реализация на С++

Сортировка основана на применении структуры данных - пирамида (сортирующего дерева, кучи). Пирамида - двоичное дерево, для которого выполняются условия:
  1. Значение в любой вершине не меньше, чем значения её потомков.
  2. Глубина листьев (расстояние до корня) отличается не более чем на 1 слой.
  3. Последний слой заполняется слева направо
Пример представления массива в виде пирамиды:

Для организации такой кучи мы будем использовать одномерный массив. Для того, чтобы свойства кучи выполнялись, нужна функция, к-ая Max_Heapify(A,i), где i - индекс массива. Она опускает значение элемента A[i] вниз по пирамиде, до тех пор, пока поддерево с корнем отвечающим элементу A[i] не становится невозрастающей пирамидой, то есть все элементы ОТСОРТИРОВАНЫ. (или по другому бинарное дерево сбалансировано)
Пример работы Max_Heapify можно почитать на вики : Max_Heapify Example

Для доступа к родительскому элементу правому и левому дочерним элементам реализуем встраиваемые функции:

inline unsigned Parent(unsigned i) {
 return floor((double)(i/2));
}

inline unsigned Left(unsigned i) {
 return ((2*i)+1);
}

inline unsigned Right(unsigned i) {
 return ((2*i)+2);
}
Реализуем функцию проталкивания меньшего элемента вниз пирамиды.
Пример проталкивания:



template < typename Type>
void Max_Heapify(Type mas[], unsigned index, unsigned heap_size){
 unsigned l=Left(index); //индекс лев. дочернего эл-та
 unsigned r=Right(index);  //индекс прав. дочернего эл-та

 unsigned largest; //хранит индекс большего эл-та
 if ((l< heap_size l="l" mas="mas">mas[index])) { //проверка, что левый элемент больше
  largest=l; //левый дочерний элемент больший элемент
 }
 else 
  largest=index; //mas[index] - больший элемент
 if ((r< heap_size mas="mas" r="r">mas[largest]))
  largest=r;
 if (largest!=index){ //если есть из дочерних элементов большие
  swap(mas[index],mas[largest]); //обменяемся с большим
  Max_Heapify(mas,largest, heap_size); //вызовем рекурсивно опять для того же элемента
 }
}

Для построения пирамиды из массива реализуем процедуру Build_Max_Heap
template < typename Type>
void Build_Max_Heap (Type mas[], unsigned heap_size){
 for (unsigned index=Parent(heap_size-1); index>0; index--){
  Max_Heapify(mas, index, heap_size);
 }
}
Теперь реализуем саму сортировку. Сначала строим пирамиду, потом будем удалять элементы из корня пирамиды и перестраивать дерево.

template < typename Type>
void Heapsort(Type mas[], unsigned mas_size){
 unsigned heap_size=mas_size;
 Build_Max_Heap(mas,heap_size);
 for (unsigned index=mas_size-1; index>=1; index--){
  swap(mas[0],mas[index]);
  heap_size--;
  Max_Heapify(mas,0, heap_size);
 }
}

Пирамидальная сортировка для ленивых :D

template < typename Iterator>
void heapsort(Iterator begin, Iterator end)
{
    std::make_heap(begin, end);
    std::sort_heap(begin, end);
}
int main {
    double valsToSort[] = {9,4,2,1,5,6};
    const int VSIZE = sizeof(valsToSort)/sizeof(*valsToSort);
    heapsort(valsToSort, valsToSort+VSIZE); 
}

пятница, 4 января 2013 г.

Реализация сортировки слиянием (Merge Sort) на С++



const int INFINITY=1E10;

template < typename Type>
void Merge(Type mas[], int left, int m, int right) {
 int n1=m-left+1;
 int n2=right-m;
 vector < Type> L(n1+1);
 vector < Type> R(n2+1);
 for (int i=0; i< n1; ++i){
  L[i]=mas[left+i];
 }
 for (int i=0; i< n2; ++i){
  R[i]=mas[m+i+1];
 }

 L[n1]=INFINITY;
 R[n2]=INFINITY;

 for (int k=left,i=0,j=0;k< =right;++k) {
  if (L[i]< =R[j]){
   mas[k]=L[i]; 
   i++;
  }
  else {
   mas[k]=R[j];
   j++;
  }
 }
}

template < typename Type>
void Merge_Sort (Type mas[], int l, int r) {
 if (l>=r) return;
 int middle=(l+r)/2;
 Merge_Sort (mas,l,middle);
 Merge_Sort(mas,middle+1,r);
 Merge(mas,l,middle,r);
}

Сортировка вставками (Insertion Sort) + Реализация С++

Предположим, что у нас массив разбит на 2 части : отсортированную и не отсортированную. 
Основная идея сортировки вставками состоит в том, что при добавлении нового элемента в уже отсортированный список его стоит сразу вставлять в нужное место, а затем заново сортировать весь список. 
Этот процесс повторяется до тех пор, пока весь массив не станет отсортированным. В процессе работы меняются местами только соседние элементы.
В худшем случае сложность алгоритма : O(n^2), время работы алгоритма будет меньше, если большая часть массива уже отсортирована. Плюс в том, что требуется O(1) дополнительной памяти.
Реализация:




template < typename Type>
void Insertion_Sort(Type mas[],unsigned long size){
 Type temp;
 unsigned long index;
 unsigned long prevIndex;
 for (index=0; index=0 && mas[prevIndex]>temp;prevIndex--)
   mas[prevIndex+1]=mas[prevIndex]; //пока у нас пред. индекс >=0 и если пред элемент>a[index]
  mas[prevIndex+1]=temp; //заменим элемент
 }
}

четверг, 3 января 2013 г.

Сортировка пузырьком (Bubble Sort) + Реализация С++

Идея сортировки пузырьком состоит в том, что на каждой итерации попарно сравниваются элементы и если элементы находятся в неправильном порядке, происходит их обмен.
Время работы O(n^2)
Алгоритм:

  1. Начинаем с конца массива, берем элемент a[j], где j=n-1 и сравниваем попарно элементы a[j] и a[j-1]
  2. Если a[j]<a[j-1], то swap(a[j],a[j-1]), т.е. более легкий элемент всплывает
  3. Уменьшаем j и повторяем до тех пор, пока выполняетсяс j>i
Графическая иллюстрация (стырено с algolist):



Реализация:

template < typename Type >
void Bubble_Sort(Type mas[], unsigned long size){
 for (unsigned long i=0; i< size; i++)
  for (unsigned long j=size-1; j > i; j--)
   if (mas[j]< mas[j-1])
    swap (mas[j],mas[j-1]);
}

Сортировка выбором (Selection Sort) + Реализация С++

Идея сортировки выбором состоит в том, что на i-ом шаге итерации ищется минимальный элемент в одномерном массиве размером n и этот элемент меняется местами с i-эм элементом массива. т.е. swap(min(к-ый нашли),a[i]). В результате
Время работы алгоритма O(n^2), так как для нахождения минимального элемента происходит n сравнений + по в процессе увеличения количества итераций, число сравнений уменьшается(n-1,n-2...1)
Алгоритм:

  1. находим номер минимального значения в текущем списке
  2. производим обмен этого значения со значением первой неотсортированной позиции (обмен не нужен, если минимальный элемент уже находится на данной позиции)
  3. теперь сортируем хвост списка, исключив из рассмотрения уже отсортированные элементы


Пример можно посмотреть здесь (стырено с algolist)


Реализация:


template < typename Type>
void Selection_Sort(Type mas[], unsigned long size){
 unsigned long minIndex;
 for (unsigned long i=0; i< size; i++){
  minIndex=i;
  for (unsigned long j=i+1; j< size; j++){
   if (mas[j]< mas[minIndex])
    minIndex=j;
  }
  if (minIndex!=i){
   swap(mas[minIndex],mas[i]);
  }
 }
}

понедельник, 31 декабря 2012 г.

Топологическая сортировка+Поиск кратчайшего пути

Топологическая сортировка - линейное упорядочивание всех его вершин. Предположим, что граф не содержит циклов, так как если он содержит циклы, то такая сортировка не возможна.

Граф, который не содержит циклов, называется ациклическим.

Ориентированные ациклические графы используются для указания последовательности действия, где каждое действие зависит от других. Например: установка программ с помощью системы управления пакетами или сборка с помощью Makefil'ов. (wikipedie (c))

Топологическая сортировка проводится с помощью поиска в глубину, которая описана в моем блоге: Поиск в глубину
Суть топологической сортировки можно связать с временем закрытия. Чем больше время закрытия, тем первее будет вершина графа в сортировке.
Пример отсортированного графа:


На рисунке представлена последовательность одевания утром. Первым делом идут носки (socks), потом трусы (undershorts) и самым последним идет пиджак у него время закрытия 4.

Для реализации топологической сортировки нам всего лишь нужно добавить в реализацию поиска в глубину глобальный стэк для вершин - stack<unsigned int> answer;
И! где мы красим вершину в черный после цикла, добавим добавление вершины в стек:

answer.push(u);
Теперь нам осталось всего лишь вывести стек) Вот и получили ответ.

Приложение: поиск кратчайшего пути в ациклическом графе.
Алгоритм выглядит так:

  1. Сначала делаем топологическую сортировку графа
  2. Для каждой вершины u в порядке топологической сортировки
    1. Для каждой смежной вершине v к вершине u
      1. Делаем релаксацию, т.е. запускаем старую добрую RELAX(u,v,w)