├── .gitignore ├── source ├── resources.rst ├── index.rst ├── bucketsort.rst ├── radixsort.rst ├── scalability.rst ├── countsort.rst ├── heap_sort.rst ├── quicksort.rst ├── conf.py └── bigoh.rst └── Makefile /.gitignore: -------------------------------------------------------------------------------- 1 | build/* 2 | *rst~ 3 | -------------------------------------------------------------------------------- /source/resources.rst: -------------------------------------------------------------------------------- 1 | To Review 2 | ============== 3 | 4 | Задача RMQ — 1. Static RMQ http://habrahabr.ru/blogs/algorithm/114980/ 5 | Поиск k-ого наименьшего элемента — http://habrahabr.ru/blogs/algorithm/115018/ 6 | B-tree — http://habrahabr.ru/blogs/algorithm/114154/ 7 | -------------------------------------------------------------------------------- /source/index.rst: -------------------------------------------------------------------------------- 1 | .. Algo book documentation master file, created by 2 | sphinx-quickstart on Sun Mar 6 17:01:35 2011. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to Algo book's documentation! 7 | ===================================== 8 | 9 | Contents: 10 | 11 | .. toctree:: 12 | :maxdepth: 2 13 | 14 | bigoh 15 | scalability 16 | resources 17 | heap_sort 18 | countsort.rst 19 | 20 | Indices and tables 21 | ================== 22 | 23 | * :ref:`genindex` 24 | * :ref:`modindex` 25 | * :ref:`search` 26 | 27 | -------------------------------------------------------------------------------- /source/bucketsort.rst: -------------------------------------------------------------------------------- 1 | Карманная сортировка 2 | ======================================== 3 | 4 | Если входные элементы подчиняются равномерному распределению, то время выполнения алгоритма карманной сортировки линейно зависит от количества входных данных. Если при сортировки методом подсчета предполагается, что входные данные целочисленны и положительны, то при карманной сортировке предполагается, что они равномерно распределены в интервале от [0, 1)/ 5 | 6 | Идея, данного алгоритма заключается в том, чтобы разбить интервал от [0, 1) на n одинаковых интервалов, или карманов (buckets), а затем равномерно распределить по этим карманам n входных величин. Поскольку входные числа равномерно распределены в интервале [0,1), мы предполагаем, что в каждый из карманов попадет не много элементов. Чтобы получить выходную последовательность, нужно просто выполнить сортировку чисел в каждом кармане, а затем последовательно перечислить элементы каждого кармана. 7 | 8 | Реализация алгоритма на Java 9 | ---------------------------- 10 | 11 | :: 12 | 13 | private double arr[]; 14 | private LinkedList buckets[]; 15 | 16 | public BucketSort(double array[]){ 17 | arr = array; 18 | } 19 | 20 | public LinkedList sort(){ 21 | int length = arr.length; 22 | buckets = new LinkedList[arr.length]; 23 | 24 | for (int j = 0; j < buckets.length; j++){ 25 | buckets[j] = new LinkedList(); 26 | } 27 | 28 | for (int i = 0; i < arr.length; i++){ 29 | int bucketIndex = (int) Math.floor((arr[i] * length)); 30 | buckets[bucketIndex].add(arr[i]); 31 | } 32 | 33 | // сортируем каждый список 34 | for (int j = 0; j < buckets.length; j++){ 35 | sortBucketElements(buckets[j]); 36 | } 37 | 38 | // объединяем элементы списков 39 | return unionBuckets(buckets); 40 | } 41 | 42 | private void sortBucketElements(LinkedList list){ 43 | 44 | for (int j = 1; j < list.size(); j++){ 45 | double key = list.get(j); 46 | int i = j - 1; 47 | 48 | while ((i > -1) && (list.get(i) > key)){ 49 | list.set(i + 1, list.get(i)); 50 | --i; 51 | } 52 | 53 | list.set(i + 1, key); 54 | } 55 | } 56 | 57 | private LinkedList unionBuckets(LinkedList buckets[]){ 58 | LinkedList outputList = new LinkedList(); 59 | 60 | for (int i = 0; i < buckets.length; i++){ 61 | outputList.addAll(buckets[i]); 62 | } 63 | 64 | return outputList; 65 | } 66 | 67 | 68 | Анализ времени выполнения алгоритма 69 | ----------------------------------- 70 | 71 | -------------------------------------------------------------------------------- /source/radixsort.rst: -------------------------------------------------------------------------------- 1 | Алгоритм поразрядной сортировки (radix sort) 2 | ============================================ 3 | 4 | История 5 | ------- 6 | Данный алгоритм применялся при сортировке перфокарт. 7 | 8 | Описание 9 | -------- 10 | Сортировка производится в цикле (k проходов цикла, где k - количество разрядов) от младшего разряда до старшего. В теле цикла разряды сортируются устойчивым алгоритмом сортировки, например алгоритмом сортировки подсчетом. 11 | 12 | Реализация алгоритма на языке Java 13 | ---------------------------------- 14 | :: 15 | 16 | public void sort(int maxLastDigitIndex){ 17 | LinkedList q[] = new LinkedList[10]; 18 | maxDigitIndex = maxLastDigitIndex; 19 | 20 | for (int i = 0; i < 10; i++){ 21 | q[i] = new LinkedList(); 22 | } 23 | 24 | for (int k = 0; k <= maxDigitIndex; k++){ 25 | for (int j = 0; j < arr.length; j++){ 26 | String temp = String.valueOf(arr[j]); 27 | int digit = Character.digit(temp.charAt(maxDigitIndex - k), 10); 28 | 29 | q[digit].addLast(arr[j]); 30 | } 31 | int num = 0; 32 | for (int s = 0; s < q.length; s++){ 33 | while (!(q[s].isEmpty())){ 34 | arr[num] = q[s].pollFirst(); 35 | ++num; 36 | } 37 | } 38 | } 39 | } 40 | 41 | В данной реализации используются очереди, для временного хранения элементов сортируемого массива. Каждый элемент сортируемого массива помещается в очередь с индексом, равным разряду числа. Затем элементы извлекаются из очередей и помещаются в сортируемый массив. 42 | 43 | Пример: :: 44 | 45 | int test[] = {101, 129, 148, 599, 199, 244, 577}; 46 | 47 | В очередь с индексом q[1] помещается элемент 101 48 | В очередь с индексом q[9] помещается элемент 129 49 | В очередь с индексом q[8] помещается элемент 148 50 | В очередь с индексом q[9] помещается элемент 599 51 | В очередь с индексом q[9] помещается элемент 199 52 | В очередь с индексом q[4] помещается элемент 244 53 | В очередь с индексом q[7] помещается элемент 577 54 | 101 244 577 148 129 599 199 55 | ------------------------------ 56 | В очередь с индексом q[0] помещается элемент 101 57 | В очередь с индексом q[4] помещается элемент 244 58 | В очередь с индексом q[7] помещается элемент 577 59 | В очередь с индексом q[4] помещается элемент 148 60 | В очередь с индексом q[2] помещается элемент 129 61 | В очередь с индексом q[9] помещается элемент 599 62 | В очередь с индексом q[9] помещается элемент 199 63 | 101 129 244 148 577 599 199 64 | ------------------------------ 65 | В очередь с индексом q[1] помещается элемент 101 66 | В очередь с индексом q[1] помещается элемент 129 67 | В очередь с индексом q[2] помещается элемент 244 68 | В очередь с индексом q[1] помещается элемент 148 69 | В очередь с индексом q[5] помещается элемент 577 70 | В очередь с индексом q[5] помещается элемент 599 71 | В очередь с индексом q[1] помещается элемент 199 72 | 101 129 148 199 244 577 599 73 | ------------------------------ 74 | 101 129 148 199 244 577 599 75 | 76 | 77 | Анализ времени выполнения алгоритма 78 | ----------------------------------- 79 | 80 | Алгоритм поразрядной сортировки позволяет выполнить корректную сортировку за время Thetta(d (n + k)), если устойчивая сортировка, используемая данным алгоритмом, имеет время работы Thetta(n + k). (d - количество разрядов числа, n - количество элементов массива, k - количество принимаемых значений числом, например для десятичных цифр - [0 - 9]) 81 | -------------------------------------------------------------------------------- /source/scalability.rst: -------------------------------------------------------------------------------- 1 | Scalability 2 | ============== 3 | 4 | In the course of reading lots of tech news, and occasionally hanging out with other hackers, I've come under the impression that there is some kind of intense, difficult black art to building large services that scale to 10^N number of users, for any impressive value of N. 5 | I'm a dev of 20+ years who has worked on everything from games, to desktop apps, to web apps. I worked as a front-end web development lead at Microsoft on several small web apps, and as the back-end dev on a small web service. 6 | 7 | I think I could get interviews at any number of interesting places, but if I was going for back-end work (the part that interests me), I feel like I would simply be out of my depth. How do I get there? I'm sure there are obvious answers like "read books", "learn on the job", or "try to build youtube/facebook/twitter, and succeed". So specifically, my question is for those who have already learned to build medium-to-large services: what was your path to acquiring these skills, and do you have any advice for people like me? 8 | 9 | Ans1 10 | ------- 11 | 12 | http://news.ycombinator.com/item?id=2290180 13 | 14 | I'll share my experience, which may differ from other people's. The largest system that I've worked on was Amazon S3. At the time that I worked there we were doing 100,000+ requests per second (peak), storing 100+ billion objects (aka files), and growing our stored object count by more than double every year. The most important skills for that job were distributed system theory, managing complexity, and operations. I can't explain all of these skills in depth, but I will try to give you enough pointers to learn on your own. 15 | For distributed systems there are two main things to learn from: good papers and good deployed systems. A researcher named Leslie Lamport invented a number of key ideas such as Lamport timestamps and Byzantine failure models. Some other basic ideas include quorums for replicated data storage and the linearizability consistency model. Google has published some good papers about their systems like MapReduce, BigTable, Dapper, and Percolator. Amazon's Dynamo paper was very influential. The Facebook engineering "notes" blog also has good content. Netflix has been blogging about their move to AWS. 16 | Every software engineer needs to manage complexity, but there are some kinds of complexity that only show up in big systems. First, your system's modules wil be running on many different machines. The most important advice I can give is to have your modules separated by very simple APIs. Joshua Bloch has written a great presentation on how to do that. Think about what happens when you do a rolling upgrade of a 1,000 node system. It might take days to complete. All the systems have to interoperate correctly during the upgrade. The fewer, simpler interactions between components the better. 17 | The best advice I know of about operating a big distributed system is this paper[1] by James Hamilton. I won't repeat its contents, but I can tell you that every time that we didn't follow its guidelines we ended up regretting it. The other important thing is to get really good with the Unix command line. You'll need to run ad-hoc commands on many machines, slice and dice log files, etc. 18 | How did I learn these skills? The usual mix of how people learn anything - independent study, school, and building both experimental and production systems. 19 | 20 | http://www.usenix.org/event/lisa07/tech/full_papers/hamilton/hamilton_html/ 21 | -------------------------------------------------------------------------------- /source/countsort.rst: -------------------------------------------------------------------------------- 1 | Сортировка подсчетом 2 | ======================== 3 | 4 | Сортировка подсчетом относится к семейству сортировок, которые выполняются за линейное время. Сортировка оперирует массивом, состоящим из элементов с целочисленными положительными значениями:: 5 | 6 | public CountingSort(int array[]){ 7 | arr = array; 8 | } 9 | 10 | public int[] sort(){ 11 | int C[] = new int[findMaxElement() + 1]; 12 | 13 | // инициализируем вспомогательный массив C нулями 14 | for (int i = 0; i < C.length; i++){ 15 | C[i] = 0; 16 | } 17 | 18 | // подсчитываем частоту появления значения в входном массиве 19 | for (int j = 0; j < arr.length; j++){ 20 | C[arr[j]] += 1; 21 | } 22 | 23 | // индекс i массива С показывает, какое количество элементов не превышает i 24 | for (int i = 1; i < C.length; i++){ 25 | C[i] = C[i - 1] + C[i]; 26 | } 27 | 28 | // используем вспомогательный массив B, в котором будет хранится отсортированная последовательность 29 | int B[] = new int[arr.length]; 30 | 31 | for (int i = arr.length-1; i >= 0; i--){ 32 | B[C[arr[i]]-1] = arr[i]; 33 | C[arr[i]] -= 1; 34 | } 35 | 36 | return B; 37 | } 38 | 39 | private int findMaxElement(){ 40 | int max = arr[0]; 41 | 42 | for (int i = 0; i < arr.length; i++){ 43 | if (arr[i] > max){ 44 | max = arr[i]; 45 | } 46 | } 47 | 48 | return max; 49 | } 50 | 51 | Test case 52 | ^^^^^^^^^^^^^^^^^^ 53 | :: 54 | 55 | public class CountingSortTest { 56 | @Test 57 | public void testSort() { 58 | int expected[] = {2, 3, 3, 5, 5, 8}; 59 | int test[] = {5,8,3,3,5,2}; 60 | CountingSort csort = new CountingSort(test); 61 | int result[] = csort.sort(); 62 | assertArrayEquals(expected, result); 63 | } 64 | 65 | } 66 | 67 | В алгоритме сортировки подсчетом, используются два вспомогательных массива: массив C, в ячейках которого хранится число элементов, не превышающие i, где i - значение одного из элементов в исходном массиве и массив B, в котором хранится отсортированная последовательность. Переменная k определяет размер вспомогательного массива C, зависит от максимального значения в сортируемом массиве. 68 | 69 | В первом цикле инициализируем вспомогательный массив C нулями. Во втором цикле подсчитываем частоту появления значений элементов входного массива.:: 70 | 71 | Например, сортируемая последовательность: {1,8, 5, 2, 1, 2, 5} 72 | 73 | После второго цикла массив C, будет выглядеть следующим образом: {0, 2, 0, 0, 2, 0, 0, 1}, где индекс является значением одного из элементов в сортируемой массиве. Т.е. значение 0 встречается 0 раз, значение 1 встречается 2 раза и т.д. 74 | 75 | Третий цикл определяет позиции элементов в отсортированном массиве.:: 76 | 77 | В моем примере массив C после прохода цикла будет выглядеть след. образом: {0, 2, 0, 0, 4, 0, 0, 7}. Например, количество элементов, не превышающих значения 1 равно 2, или количество элементов, не превышающих значения 7 равно 7. 78 | 79 | В четвертом цикле элемент из сортируемого массива arr, устанавливается в позицию отсортированного массива B. Позиции хранятся в вспомогательном массиве C. Если количество элементов, не превышающих значения 1 равно 2, то элемент устанавливается в 2-ую позицию массива B. 80 | 81 | 82 | Анализ времени выполнения алгоритма сортировки подсчетом 83 | -------------------------------------------------------- 84 | 85 | Первый цикл выполняется за время Thetta(k), второй за время Thetta(n), третий за время Thetta(k), четвертый за время Thetta(n). Таким образом, полное время выполнения алгоритма равно Thetta(n + k). На практике сортировка подсчетом применяется, когда k = O(n), а в этом случае время работы алгоритма равно Thetta(n). 86 | 87 | Свойство устойчивости 88 | --------------------- 89 | Важное свойство алгоритма сортировки подсчетом заключается в том, что он устойчив: элементы с одним и тем же входным значением находятся в выходном массиве, в том же порядке, что и во входном. Обычно свойство устойчивости важно только в ситуации, когда вместе сортируемые элементы имеют сопутствующие данные. 90 | 91 | 92 | Выводы 93 | ------------------- 94 | 95 | Сортировка подсчетом используется, когда входные данные положительны, целочисленны и их значения изменяются в небольшом интервале. 96 | -------------------------------------------------------------------------------- /source/heap_sort.rst: -------------------------------------------------------------------------------- 1 | Алгоритмы сортировки 2 | ==================== 3 | Пирамидальная сортировка 4 | ------------------------ 5 | 6 | Пирамидальная сортировка основана на использовании структуры данных пирамида (heap). Это структура данных представляет собой бинарное дерево. Каждый узел дерева соответствует элементу массива. Последний уровень заполняется слева направо. 7 | 8 | Рассмотрим вспомогательные методы, которые использует пирамидальная сортировка. 9 | 10 | Метод Parent(i) возвращает индекс родительского узла i:: 11 | 12 | private int parent(int i){ 13 | return i/2; 14 | } 15 | 16 | Метод left(i) - получение индекса левого дочернего узла, где i - родительский узел:: 17 | 18 | private int left(int i){ 19 | return 2*i; 20 | } 21 | 22 | Метод right(i) - получение индекса правого дочернего узла, где i - родительский узел:: 23 | 24 | private int right(int i){ 25 | return 2*i + 1; 26 | } 27 | 28 | Замечание: 29 | Метод parent(i) возвращает наименьшее целое число, при передаче ему нечетного числа. 30 | 31 | Невозрастающая пирамида 32 | Пирамида является **невозрастающей** в том случае, когда значения дочерних узлов меньше, либо равны значению родительского узла. 33 | 34 | Неубывающая пирамида 35 | Пирамида является **неубывающей** в том случае, когда значения дочерних узлов больше, либо равны значению родительского узла. 36 | 37 | Метод heapify(A,i) - поддерживает свойство невозрастающей пирамиды:: 38 | 39 | private void heapify(Integer i){ 40 | int largest; 41 | int left = left(i); 42 | int right = right(i); 43 | 44 | if ((left < heapSize) && (arr[left] > arr[i])){ 45 | largest = left; 46 | } 47 | else{ 48 | largest = i; 49 | } 50 | 51 | if ((right < heapSize) && (arr[right] > arr[largest])){ 52 | largest = right; 53 | } 54 | 55 | if (i != largest){ 56 | int temp = arr[i]; 57 | arr[i] = arr[largest]; 58 | arr[largest] = temp; 59 | this.heapify(largest); 60 | } 61 | } 62 | 63 | В методе есть дополнительные проверки, типа (left < heapSize) и (right < heapSize). Методы left(i) и right(i) могут вернуть такой индекс, который не входит в пирамиду. Метод является рекурсивным, после обмена значениями дочерних узлов и родительского узла, повторно вызывается этот же метод, которому передается индекс узла с наибольшим значением. 64 | 65 | Конструктор Heap(A) - создает невозрастающую пирамиду из элементов массива:: 66 | 67 | public Heap(Integer A[]){ 68 | arr = A; 69 | heapSize = A.length; 70 | 71 | // создаем пирамиду 72 | for (int i = arr.length/2 - 1; i >= 0; i--){ 73 | heapify(i); 74 | } 75 | } 76 | 77 | Функция heapSort(A) - пирамидальная сортировка.:: 78 | 79 | public void heapSort(){ 80 | int arrLength = heapSize; 81 | 82 | for (int i = arrLength-1; i >= 1; i--){ 83 | int temp = arr[0]; 84 | arr[0] = arr[i]; 85 | arr[i] = temp; 86 | 87 | --heapSize; 88 | heapify(0); 89 | } 90 | } 91 | 92 | В теле цикла значениями обмениваются корневой узел пирамиды arr[0] и последний элемент пирамиды (leaf node). После чего, размер пирамиды уменьшается, узел таким образом отсекается, и вызывается метод поддержания свойства невозрастания пирамиды heapify(0). Вызов метод нужен потому, что в корне пирамиды после обмена содержится наименьшее значение. 93 | 94 | Анализ времени выполнения алгоритма 95 | ----------------------------------- 96 | 97 | Метод left(i) выполняется очень быстро, путем битового сдвига числа i влево на одну позицию:: 98 | 99 | i = 3 = 11; 100 | i = 2*3 = 110 101 | 102 | i = 8 = 1000 103 | i = 8*2 = 10000 104 | 105 | Метод right(i) тоже выполняется очень быстро, путем битового сдвига числа i влево на одну позицию и установки младшего бита в единицу:: 106 | 107 | i = 3 = 11; 108 | i = 2*3 + 1 = 111 109 | 110 | i = 8 = 1000 111 | i = 8*2 + 1 = 1001 112 | 113 | Время работы метода heapify(i) в заданном узле i, вычисляется как время \theta (1), необходимое для исправления отношений между элементами arr[i], arr[left(i)] или arr[right(i)], плюс время работы метода с поддеревом, корень которого находится в одном из дочерних узлов i. Время работы метода heapify(i) c узлом i, находящимся на высоте h, можно выразить как О(h) или O(lgn); 114 | 115 | Высота узла определяется как количество его предков. Высоту дерева определяют по высоте его узлов листьев (leaf nodes). 116 | 117 | Время работы метода heapsort() равно О(nlgn), поскольку вызов метода Heap() требует времени O(n), а каждый из n-1 вызовов метода heapify - времени O(lgn) 118 | 119 | Сравнение со временем выполнения других алгоритмов сортировки 120 | ------------------------------------------------------------- 121 | 122 | -------------------------------------------------------------------------------- /source/quicksort.rst: -------------------------------------------------------------------------------- 1 | Семейство быстрых сортировок 2 | ========================================= 3 | 4 | Быстрая сортировка - это алгоритм сортировки, время работы которого для входного массива из n чисел в наихудшем случае равно tetta(n^2). Несмотря на такую медленную работу, в среднем время выполнения алгоритма намного лучше O(n^2). 5 | 6 | Описание быстрой сортировки 7 | --------------------------- 8 | 9 | Алгоритм быстрой сортировки основан на парадигме "разделяй и властвуй". Процесс сортировки подмассива A[p...r] состоит из трех этапов: 10 | 11 | **Разделение** 12 | Массив A[p...r] разбивается на два подмассива (путем переупорядочения его элементов) A[p...q-1] и A[q+1...r]. Каждый элемент в подмассиве A[p...q-1] не превышает значения элемента A[q]; элементы в подмассиве A[q+1...r] больше элемента A[q]. Индекс q вычисляется в ходе выполнения процедуры. 13 | 14 | **Покорение** 15 | Подмассивы A[p...q-1] и A[q+1...r] сортируются путем вызова процедуры быстрой сортировки. 16 | 17 | **Комбинирование** 18 | Поскольку подмассивы сортируются на месте, для их объединения не нужны никакие действия; весь массив A[p...r] оказывается отсортированным. 19 | 20 | 21 | Реализация алгоритма быстрой сортировки на языке Java 22 | --------------------------------- 23 | 24 | Метод quicksort():: 25 | 26 | public void qsort(int p, int r){ 27 | if (p < r){ 28 | int q = partition(p, r); 29 | sort(p, q - 1); 30 | sort(q + 1, r); 31 | } 32 | } 33 | 34 | Метод разбиения массива partition(p,r):: 35 | 36 | private int partition(int p, int r){ 37 | int x = arr[r]; 38 | int i = p - 1; 39 | 40 | for (j = p; j < r - 1; j++){ 41 | if (arr[j] <= x){ 42 | ++i; 43 | int temp = arr[i]; 44 | arr[i] = arr[j]; 45 | arr[j] = temp; 46 | } 47 | } 48 | 49 | int temp = arr[i+1]; 50 | arr[i+1] = arr[r]; 51 | arr[r] = temp; 52 | 53 | return i + 1; 54 | } 55 | 56 | Анализ времени выполнения алгоритма быстрой сортировки 57 | ------------------------- 58 | 59 | Время выполнения алгоритма быстрой сортировки зависит от того, какой элемент выбран в качестве опорного (pivot) т.е. от **степени сбалансированности**. Если разбиение сбалансированное, то алгоритм работает так же быстро, как и сортировка слиянием, в противном случае время выполнения алгоритма такое же как и у алгоритма сортировки вставкой. 60 | 61 | Наихудшее разбиение 62 | ^^^^^^^^^^^^^^^^^^^ 63 | 64 | Наихудшее разбиение имеет место быть, когда процедура разбиения возвращает два подмассива: один длиной 0 элементов, второй n-1. 65 | 66 | Рекуррентное соотношение, описывающее время работы процедуры сортировки массива:: 67 | 68 | T(n) = Thetta(n) + T(0) + T(n-1) = Thetta(n) + T(n-1) 69 | 70 | Время, затрачиваемое на разделение массива на подмассивы равно Thetta(n), т.к. выполняется сравнение каждого элемента массива с значением опорного элемента n раз. Время выполнения процедуры quicksort(p,0) равно 0, т.к. процедура сразу же завершает свое выполнение. Методом подстановки T(n - 1) = Θ(n-1) + T(n - 2) мы можем получить следующее выражение:: 71 | 72 | T(n) = Thetta(n) + Thetta(n - 1) + Thetta(n - 2) + ... = Thetta(n^2) 73 | 74 | Таким образом, если на каждом уровне рекурсии разбиение максимально несбалансированное, то время выполнения алгоритма быстрой сортировки равно Thetta(n^2). 75 | 76 | Примечание от автора: 77 | Думаю, что наихудшее разбиение возникает тогда, когда массив отсортирован в порядке убывания, а процедура сортировки выполняет сортировку такого массива по возрастанию. В этом случае опорный элемент становится минимальным, и следовательно процедура разбиения будет возвращать q = 1, что породит два подмассива, один длиной 0 элементов, другой n - 1 элементов. 78 | 79 | Наилучшее разбиение 80 | ^^^^^^^^^^^^^^^^^^^ 81 | 82 | В самом благоприятном случае процедура разбиения массива делит задачу на две подзадачи, размер каждой из которых не превышает n/2. В этом случае алгоритм быстрой сортировки работает намного быстрее, время работы описывается следующим рекурректным уравнением:: 83 | 84 | T(n) <= 2T(n/2) + Thetta(n) 85 | T(n) = O(n lgn) 86 | 87 | Сбалансированное разбиение 88 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ 89 | 90 | Разбиение даже в соотношении девяносто девять к одному приводит к тому, что время выполнения алгоритма будет равно О(nlgn). Несмотря на то, что такое разбиение выглядит несбалансированным, в асимптотическом пределе алгоритм ведет себя так же, как и при делении задачи на две одинаковые подзадачи. 91 | 92 | 93 | Рандомизированная быстрая сортировка 94 | ------------------------------------ 95 | 96 | Исследуя поведение алгоритма быстрой сортировки в среднем случае, мы сделали предположение, что все элементы встречаются с равной вероятностью. Однако на практике это далеко не всегда так. Путем добавления этапа рандомизации можно получить среднюю производительность во всех случаях. Многие считают такую версию быстрой сортировки оптимальной для обработки больших массивов. 97 | 98 | Случайная выборка 99 | ^^^^^^^^^^^^^^^^^ 100 | 101 | Вместо того, чтобы в качестве опорного элемента подмассива выбирать всегда элемент arr[r], можно выбрать случайный элемент среди элементов с индексами от p до r. Благодаря случайному выбору опорного элемента, можно ожидать что разбиение в среднем случае окажется довольно сбалансированным. 102 | 103 | private int randomPartition(int p, int r){ 104 | int indexes = p - r; 105 | 106 | if (indexes > 0){ 107 | int rnd = generator.nextInt(indexes); 108 | 109 | int temp = arr[r]; 110 | arr[r] = arr[rnd]; 111 | arr[rnd] = temp; 112 | } 113 | 114 | return partition(p, r); 115 | } 116 | 117 | private int randomPartition(int p, int r){ 118 | int indexes = p - r; 119 | 120 | if (indexes > 0){ 121 | int rnd = generator.nextInt(indexes); 122 | int temp = arr[r]; 123 | arr[r] = arr[rnd]; 124 | arr[rnd] = temp; 125 | } 126 | 127 | return partition(p, r); 128 | } 129 | 130 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = build 9 | 10 | # Internal variables. 11 | PAPEROPT_a4 = -D latex_paper_size=a4 12 | PAPEROPT_letter = -D latex_paper_size=letter 13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 14 | 15 | tmp_docs_dir=/tmp/algo-tmp-docs 16 | 17 | .PHONY: help clean html ghdocs dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest 18 | 19 | help: 20 | @echo "Please use \`make ' where is one of" 21 | @echo " html to make standalone HTML files" 22 | @echo " dirhtml to make HTML files named index.html in directories" 23 | @echo " singlehtml to make a single large HTML file" 24 | @echo " pickle to make pickle files" 25 | @echo " json to make JSON files" 26 | @echo " htmlhelp to make HTML files and a HTML help project" 27 | @echo " qthelp to make HTML files and a qthelp project" 28 | @echo " devhelp to make HTML files and a Devhelp project" 29 | @echo " epub to make an epub" 30 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 31 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 32 | @echo " text to make text files" 33 | @echo " man to make manual pages" 34 | @echo " changes to make an overview of all changed/added/deprecated items" 35 | @echo " linkcheck to check all external links for integrity" 36 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 37 | 38 | clean: 39 | -rm -rf $(BUILDDIR)/* 40 | 41 | html: 42 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 43 | @echo 44 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 45 | 46 | ghdocs: 47 | rm -rf $(tmp_docs_dir) 48 | mkdir $(tmp_docs_dir) 49 | $(MAKE) html 50 | cp -r build/html/* $(tmp_docs_dir) 51 | mv $(tmp_docs_dir)/_static $(tmp_docs_dir)/static 52 | mv $(tmp_docs_dir)/_sources $(tmp_docs_dir)/sources 53 | perl -pi -e "s/_sources/sources/g;" $(tmp_docs_dir)/*.html 54 | perl -pi -e "s/_static/static/g;" $(tmp_docs_dir)/*.html 55 | git checkout gh-pages 56 | rm -r sources static & 2>/dev/null 57 | cp -rf $(tmp_docs_dir)/* . 58 | rm -rf build 59 | git add -A 60 | git commit -a -m 'Updates $(project) documentation.' || 2> cat 61 | git checkout master 62 | rm -rf $(tmp_docs_dir) 63 | 64 | dirhtml: 65 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 66 | @echo 67 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 68 | 69 | singlehtml: 70 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 71 | @echo 72 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 73 | 74 | pickle: 75 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 76 | @echo 77 | @echo "Build finished; now you can process the pickle files." 78 | 79 | json: 80 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 81 | @echo 82 | @echo "Build finished; now you can process the JSON files." 83 | 84 | htmlhelp: 85 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 86 | @echo 87 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 88 | ".hhp project file in $(BUILDDIR)/htmlhelp." 89 | 90 | qthelp: 91 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 92 | @echo 93 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 94 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 95 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Algobook.qhcp" 96 | @echo "To view the help file:" 97 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Algobook.qhc" 98 | 99 | devhelp: 100 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 101 | @echo 102 | @echo "Build finished." 103 | @echo "To view the help file:" 104 | @echo "# mkdir -p $$HOME/.local/share/devhelp/Algobook" 105 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Algobook" 106 | @echo "# devhelp" 107 | 108 | epub: 109 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 110 | @echo 111 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 112 | 113 | latex: 114 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 115 | @echo 116 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 117 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 118 | "(use \`make latexpdf' here to do that automatically)." 119 | 120 | latexpdf: 121 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 122 | @echo "Running LaTeX files through pdflatex..." 123 | make -C $(BUILDDIR)/latex all-pdf 124 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 125 | 126 | text: 127 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 128 | @echo 129 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 130 | 131 | man: 132 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 133 | @echo 134 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 135 | 136 | changes: 137 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 138 | @echo 139 | @echo "The overview file is in $(BUILDDIR)/changes." 140 | 141 | linkcheck: 142 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 143 | @echo 144 | @echo "Link check complete; look for any errors in the above output " \ 145 | "or in $(BUILDDIR)/linkcheck/output.txt." 146 | 147 | doctest: 148 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 149 | @echo "Testing of doctests in the sources finished, look at the " \ 150 | "results in $(BUILDDIR)/doctest/output.txt." 151 | -------------------------------------------------------------------------------- /source/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Algo book documentation build configuration file, created by 4 | # sphinx-quickstart on Sun Mar 6 17:01:35 2011. 5 | # 6 | # This file is execfile()d with the current directory set to its containing dir. 7 | # 8 | # Note that not all possible configuration values are present in this 9 | # autogenerated file. 10 | # 11 | # All configuration values have a default; values that are commented out 12 | # serve to show the default. 13 | 14 | import sys, os 15 | 16 | # If extensions (or modules to document with autodoc) are in another directory, 17 | # add these directories to sys.path here. If the directory is relative to the 18 | # documentation root, use os.path.abspath to make it absolute, like shown here. 19 | #sys.path.insert(0, os.path.abspath('.')) 20 | 21 | # -- General configuration ----------------------------------------------------- 22 | 23 | # If your documentation needs a minimal Sphinx version, state it here. 24 | #needs_sphinx = '1.0' 25 | 26 | # Add any Sphinx extension module names here, as strings. They can be extensions 27 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 28 | extensions = [] 29 | 30 | # Add any paths that contain templates here, relative to this directory. 31 | templates_path = ['_templates'] 32 | 33 | # The suffix of source filenames. 34 | source_suffix = '.rst' 35 | 36 | # The encoding of source files. 37 | #source_encoding = 'utf-8-sig' 38 | 39 | # The master toctree document. 40 | master_doc = 'index' 41 | 42 | # General information about the project. 43 | project = u'Algo book' 44 | copyright = u'2011, Vladimir Shulyak' 45 | 46 | # The version info for the project you're documenting, acts as replacement for 47 | # |version| and |release|, also used in various other places throughout the 48 | # built documents. 49 | # 50 | # The short X.Y version. 51 | version = '1.0' 52 | # The full version, including alpha/beta/rc tags. 53 | release = '1.0' 54 | 55 | # The language for content autogenerated by Sphinx. Refer to documentation 56 | # for a list of supported languages. 57 | #language = None 58 | 59 | # There are two options for replacing |today|: either, you set today to some 60 | # non-false value, then it is used: 61 | #today = '' 62 | # Else, today_fmt is used as the format for a strftime call. 63 | #today_fmt = '%B %d, %Y' 64 | 65 | # List of patterns, relative to source directory, that match files and 66 | # directories to ignore when looking for source files. 67 | exclude_patterns = [] 68 | 69 | # The reST default role (used for this markup: `text`) to use for all documents. 70 | #default_role = None 71 | 72 | # If true, '()' will be appended to :func: etc. cross-reference text. 73 | #add_function_parentheses = True 74 | 75 | # If true, the current module name will be prepended to all description 76 | # unit titles (such as .. function::). 77 | #add_module_names = True 78 | 79 | # If true, sectionauthor and moduleauthor directives will be shown in the 80 | # output. They are ignored by default. 81 | #show_authors = False 82 | 83 | # The name of the Pygments (syntax highlighting) style to use. 84 | pygments_style = 'sphinx' 85 | 86 | # A list of ignored prefixes for module index sorting. 87 | #modindex_common_prefix = [] 88 | 89 | 90 | # -- Options for HTML output --------------------------------------------------- 91 | 92 | # The theme to use for HTML and HTML Help pages. See the documentation for 93 | # a list of builtin themes. 94 | html_theme = 'default' 95 | 96 | # Theme options are theme-specific and customize the look and feel of a theme 97 | # further. For a list of options available for each theme, see the 98 | # documentation. 99 | #html_theme_options = {} 100 | 101 | # Add any paths that contain custom themes here, relative to this directory. 102 | #html_theme_path = [] 103 | 104 | # The name for this set of Sphinx documents. If None, it defaults to 105 | # " v documentation". 106 | #html_title = None 107 | 108 | # A shorter title for the navigation bar. Default is the same as html_title. 109 | #html_short_title = None 110 | 111 | # The name of an image file (relative to this directory) to place at the top 112 | # of the sidebar. 113 | #html_logo = None 114 | 115 | # The name of an image file (within the static path) to use as favicon of the 116 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 117 | # pixels large. 118 | #html_favicon = None 119 | 120 | # Add any paths that contain custom static files (such as style sheets) here, 121 | # relative to this directory. They are copied after the builtin static files, 122 | # so a file named "default.css" will overwrite the builtin "default.css". 123 | html_static_path = ['_static'] 124 | 125 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 126 | # using the given strftime format. 127 | #html_last_updated_fmt = '%b %d, %Y' 128 | 129 | # If true, SmartyPants will be used to convert quotes and dashes to 130 | # typographically correct entities. 131 | #html_use_smartypants = True 132 | 133 | # Custom sidebar templates, maps document names to template names. 134 | #html_sidebars = {} 135 | 136 | # Additional templates that should be rendered to pages, maps page names to 137 | # template names. 138 | #html_additional_pages = {} 139 | 140 | # If false, no module index is generated. 141 | #html_domain_indices = True 142 | 143 | # If false, no index is generated. 144 | #html_use_index = True 145 | 146 | # If true, the index is split into individual pages for each letter. 147 | #html_split_index = False 148 | 149 | # If true, links to the reST sources are added to the pages. 150 | #html_show_sourcelink = True 151 | 152 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 153 | #html_show_sphinx = True 154 | 155 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 156 | #html_show_copyright = True 157 | 158 | # If true, an OpenSearch description file will be output, and all pages will 159 | # contain a tag referring to it. The value of this option must be the 160 | # base URL from which the finished HTML is served. 161 | #html_use_opensearch = '' 162 | 163 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 164 | #html_file_suffix = None 165 | 166 | # Output file base name for HTML help builder. 167 | htmlhelp_basename = 'Algobookdoc' 168 | 169 | 170 | # -- Options for LaTeX output -------------------------------------------------- 171 | 172 | # The paper size ('letter' or 'a4'). 173 | #latex_paper_size = 'letter' 174 | 175 | # The font size ('10pt', '11pt' or '12pt'). 176 | #latex_font_size = '10pt' 177 | 178 | # Grouping the document tree into LaTeX files. List of tuples 179 | # (source start file, target name, title, author, documentclass [howto/manual]). 180 | latex_documents = [ 181 | ('index', 'Algobook.tex', u'Algo book Documentation', 182 | u'Vladimir Shulyak', 'manual'), 183 | ] 184 | 185 | # The name of an image file (relative to this directory) to place at the top of 186 | # the title page. 187 | #latex_logo = None 188 | 189 | # For "manual" documents, if this is true, then toplevel headings are parts, 190 | # not chapters. 191 | #latex_use_parts = False 192 | 193 | # If true, show page references after internal links. 194 | #latex_show_pagerefs = False 195 | 196 | # If true, show URL addresses after external links. 197 | #latex_show_urls = False 198 | 199 | # Additional stuff for the LaTeX preamble. 200 | #latex_preamble = '' 201 | 202 | # Documents to append as an appendix to all manuals. 203 | #latex_appendices = [] 204 | 205 | # If false, no module index is generated. 206 | #latex_domain_indices = True 207 | 208 | 209 | # -- Options for manual page output -------------------------------------------- 210 | 211 | # One entry per manual page. List of tuples 212 | # (source start file, name, description, authors, manual section). 213 | man_pages = [ 214 | ('index', 'algobook', u'Algo book Documentation', 215 | [u'Vladimir Shulyak'], 1) 216 | ] 217 | -------------------------------------------------------------------------------- /source/bigoh.rst: -------------------------------------------------------------------------------- 1 | Big O 2 | ============== 3 | 4 | http://stackoverflow.com/questions/3255/big-o-how-do-you-calculate-approximate-it 5 | 6 | Most people with a degree in CS will certainly know what Big O stands for. It helps us to measure how (in)efficient an algorithm really is and if you know in what category the problem you are trying to solve lays in you can figure out if it is still possible to squeeze out that little extra performance.1 7 | 8 | But I'm curious, how do you calculate or approximate the complexity of your algorithms? 9 | 10 | One 11 | ----------- 12 | 13 | Big O gives the upper bound for time complexity of an algorithm. It is usually used in conjunction with processing data sets (lists) but can be used elsewhere. 14 | 15 | A few examples of how it's used in C code. 16 | 17 | Say we have an array of n elements 18 | 19 | int array[n]; 20 | If we wanted to access the first element of the array this would be O(1) since it doesn't matter how big the array is, it always takes the same constant time to get the first item. 21 | 22 | x = array[0]; 23 | If we wanted to find a number in the list: 24 | 25 | for(int i = 0; i < n; i++){ 26 | if(array[i] == numToFind){ return i; } 27 | } 28 | This would be O(n) since at most we would have to look through the entire list to find our number. The Big-O is still O(n) even though we might find our number the first try and run through the loop once because Big-O describes the upper bound for an algorithm (omega is for lower bound and theta is for tight bound). 29 | 30 | When we get to nested loops: 31 | 32 | for(int i = 0; i < n; i++){ 33 | for(int j = i; j < n; j++){ 34 | array[j] += 2; 35 | } 36 | } 37 | This is O(n^2) since for each pass of the outer loop ( O(n) ) we have to go through the entire list again so the n's multiply leaving us with n squared. 38 | 39 | This is barely scratching the surface but when you get to analyzing more complex algorithms complex math involving proofs comes into play. Hope this familiarizes you with the basics at least though. 40 | 41 | Two 42 | ----------- 43 | 44 | 45 | I'm a professor assistant at my local university on the Data Structures and Algorithms course. I'll do my best to explain it here on simple terms, but be warned that this topic takes my students a couple of months to finally grasp. You can find more information on the Chapter 2 of the Data Structures and Algorithms in Java book. 46 | 47 | There is no mechanical procedure that can be used to get the BigOh. 48 | 49 | As a "cookbook", to obtain the BigOh from a piece of code you first need to realize that you are creating a math formula to count how many steps of computations gets executed given an input of some size. 50 | 51 | The purpose is simple: to compare algorithms from a theoretical point of view, without the need to execute the code. The lesser the number of steps, the faster the algorithm. 52 | 53 | For example, let's say you have this piece of code: 54 | 55 | int sum(int* data, int N) { 56 | int result = 0; // 1 57 | 58 | for (int i = 0; i < N; i++) { // 2 59 | result += data[i]; // 3 60 | } 61 | 62 | return result; // 4 63 | } 64 | This function returns the sum of all the elements of the array, and we want to create a formula to count the computational complexity of that function: 65 | 66 | Number_Of_Steps = f(N) 67 | So we have f(N), a function to count the number of computational steps. The input of the function is the size of the structure to process. It means that this function is called suchs as: 68 | 69 | Number_Of_Steps = f(data.length) 70 | The parameter N takes the data.length value. Now we need the actual definition of the function f(). This is done from the source code, in which each interesting line is numbered from 1 to 4. 71 | 72 | There are many ways to calculate the BigOh. From this point forward we are going to assume that every sentence that don't depend on the size of the input data takes a constant C number computational steps. 73 | 74 | We are going to add the individual number of steps of the function, and neither the local variable declaration nor the return statement depends on the size of the data array. 75 | 76 | That means that lines 1 and 4 takes C amount of steps each, and the function is somewhat like this: 77 | 78 | f(N) = C + ??? + C 79 | The next part is to define the value of the for statement. Remember that we are counting the number of computational steps, meaning that the body of the for statement gets executed N times. That's the same as adding C, N times: 80 | 81 | f(N) = C + (C + C + ... + C) + C = C + N * C + C 82 | There is no mechanical rule to count how many times the body of the for gets executed, you need to count it by looking at what does the code do. To simplify the calculations, we are ignoring the variable initialization, condition and increment parts of the for statement. 83 | 84 | To get the actual BigOh we need the Asymptotic analysis of the function. This is roughly done like this: 85 | 86 | Take away all the constants C. 87 | From f() get the polynomium in its standard form. 88 | Divide the terms of the polynomium and sort them by the rate of growth. 89 | Keep the one that grows bigger when N approaches infinity. 90 | Our f() has two terms: 91 | 92 | f(N) = 2 * C * N ^ 0 + 1 * C * N ^ 1 93 | Taking away all the C constants and redundant parts: 94 | 95 | f(N) = 1 + N ^ 1 96 | Since the last term is the one which grows bigger when f() approaches infinity (think on limits) this is the BigOh argument, and the sum() function has a BigOh of: 97 | 98 | O(N) 99 | There are a few tricks to solve some tricky ones: use summations whenever you can. There are some handy summation identities already proven to be correct. 100 | 101 | As another example, this code can be easily solved using summations: 102 | 103 | // A 104 | for (i = 0; i < 2*n; i += 2) { // 1 105 | for (j=n; j > i; j--) { // 2 106 | foo(); // 3 107 | } 108 | } 109 | The first thing you needed to be asked is the order of execution of foo(). While the usual is to be O(1), you need to ask your professors about it. O(1) means (almost, mostly) constant C, independent of the size N. 110 | 111 | The for statement on the sentence number one is tricky. While the index ends at 2 * N, the increment is done by two. That means that the for gets executed only N steps, and we need to divide the count by two. 112 | 113 | f(N) = Summation(i from 1 to 2 * N / 2)( ... ) = 114 | = Summation(i from 1 to N)( ... ) 115 | The sentence number two is even trickier since it depends on the value of i. Take a look: the index i takes the values: 0, 2, 4, 6, 8, ..., 2 * N, and the secondth for get executed: N times the first one, N - 2 the secondth, N - 4 the third... up to the N / 2 stage, on which the secondth for never gets executed. 116 | 117 | On formula, that means: 118 | 119 | f(N) = Summation(i from 1 to N)( Summation(j = ???)( ) ) 120 | Again, we are counting the number of steps. And by definition, every summation should always start at one, and end at a number bigger-or-equal than one. 121 | 122 | f(N) = Summation(i from 1 to N)( Summation(j = 1 to (N - (i - 1) * 2)( C ) ) 123 | (We are assuming that foo() is O(1) and takes C steps.) 124 | 125 | We have a problem here: when i takes the value N / 2 + 1 upwards, the inner Summation ends at a negative number! That's impossible and wrong. We need to split the summation in two, being the pivotal point the moment i takes N / 2 + 1. 126 | 127 | f(N) = Summation(i from 1 to N / 2)( Summation(j = 1 to (N - (i - 1) * 2)) * ( C ) ) + Summation(i from 1 to N / 2) * ( C ) 128 | Since the pivotal moment i > N / 2, the inner for wont get executed and we are assuming a constant C execution complexity on it's body. 129 | 130 | Now the summations can be simplified using some identity rules: 131 | 132 | Summation(w from 1 to N)( C ) = N * C 133 | Summation(w from 1 to N)( A (+/-) B ) = Summation(w from 1 to N)( A ) (+/-) Summation(w from 1 to N)( B ) 134 | Summation(w from 1 to N)( w * C ) = C * Summation(w from 1 to N)( w ) (C is a constant, independent of w) 135 | Summation(w from 1 to N)( w ) = (w * (w + 1)) / 2 136 | Applying some algebra: 137 | 138 | f(N) = Summation(i from 1 to N / 2)( (N - (i - 1) * 2) * ( C ) ) + (N / 2)( C ) 139 | 140 | f(N) = C * Summation(i from 1 to N / 2)( (N - (i - 1) * 2)) + (N / 2)( C ) 141 | 142 | f(N) = C * (Summation(i from 1 to N / 2)( N ) - Summation(i from 1 to N / 2)( (i - 1) * 2)) + (N / 2)( C ) 143 | 144 | f(N) = C * (( N ^ 2 / 2 ) - 2 * Summation(i from 1 to N / 2)( i - 1 )) + (N / 2)( C ) 145 | 146 | => Summation(i from 1 to N / 2)( i - 1 ) = Summation(i from 1 to N / 2 - 1)( i ) 147 | 148 | f(N) = C * (( N ^ 2 / 2 ) - 2 * Summation(i from 1 to N / 2 - 1)( i )) + (N / 2)( C ) 149 | 150 | f(N) = C * (( N ^ 2 / 2 ) - 2 * ( (N / 2 - 1) * (N / 2 - 1 + 1) / 2) ) + (N / 2)( C ) 151 | 152 | => (N / 2 - 1) * (N / 2 - 1 + 1) / 2 = 153 | 154 | (N / 2 - 1) * (N / 2) / 2 = 155 | 156 | ((N ^ 2 / 4) - (N / 2)) / 2 = 157 | 158 | (N ^ 2 / 8) - (N / 4) 159 | 160 | f(N) = C * (( N ^ 2 / 2 ) - 2 * ( (N ^ 2 / 8) - (N / 4) )) + (N / 2)( C ) 161 | 162 | f(N) = C * (( N ^ 2 / 2 ) - ( (N ^ 2 / 4) - (N / 2) )) + (N / 2)( C ) 163 | 164 | f(N) = C * (( N ^ 2 / 2 ) - (N ^ 2 / 4) + (N / 2)) + (N / 2)( C ) 165 | 166 | f(N) = C * ( N ^ 2 / 4 ) + C * (N / 2) + C * (N / 2) 167 | 168 | f(N) = C * ( N ^ 2 / 4 ) + 2 * C * (N / 2) 169 | 170 | f(N) = C * ( N ^ 2 / 4 ) + C * N 171 | 172 | f(N) = C * 1/4 * N ^ 2 + C * N 173 | And the BigOh is: 174 | 175 | O(N ^ 2) 176 | 177 | 178 | Three 179 | ------- 180 | 181 | While knowing how to figure out the Big O time for your particular problem is useful, knowing some general cases can go a long way in helping you make decisions in your algorithm. 182 | 183 | Here are some of the most common cases, lifted from http://en.wikipedia.org/wiki/Big_O_notation#Orders_of_common_functions: 184 | 185 | O(1) - Determining if a number is even or odd; using a constant-size lookup table or hash table 186 | 187 | O(logn) - Finding an item in a sorted array with a binary search 188 | 189 | O(n) - Finding an item in an unsorted list; adding two n-digit numbers 190 | 191 | O(n^2) - Multiplying two n-digit numbers by a simple algorithm; adding two n×n matrices; bubble sort or insertion sort 192 | 193 | O(n^3) - Multiplying two n×n matrices by simple algorithm 194 | 195 | O(c^n) - Finding the (exact) solution to the traveling salesman problem using dynamic programming; determining if two logical statements are equivalent using brute force 196 | 197 | O(n!) - Solving the traveling salesman problem via brute-force search 198 | 199 | O(n^n) - Often used instead of O(n!) to derive simpler formulas for asymptotic complexity 200 | 201 | --------------------------------------------------------------------------------