Algorithms Lesson 1: Bubblesort
代码
复杂度分析
n 个元素, 比较次数有 (n-1) + (n-2) + ...... + 1 = n(n-1)/2,
O(n2)
Algorithms Lesson 2: Insertion Sort
代码
换个形式
算法复杂度
Algorithms Lesson 3: Merge Sort
代码
Algorithms Lesson 4:Selection sort
代码
复杂度分析
选择排序的交换操作介于0和(n − 1)次之间。选择排序的比较操作为n(n − 1) / 2次之间。选择排序的赋值操作介于0和3(n − 1)次之间。
比较次数O(n^2),比较次数与关键字的初始状态无关,总的比较次数N=(n-1)+(n-2)+...+1=n*(n-1)/2。 交换次数O(n),最好情况是,已经有序,交换0次;最坏情况是,逆序,交换n-1次。 交换次数比冒泡排序少多了,由于交换所需CPU时间比比较所需的CPU时间多,n值较小时,选择排序比冒泡排序快。
Algorithms Lesson 5:Merge sort
算法描述
代码
算法复杂度
比较操作的次数介于(nlogn) / 2和nlogn − n + 1。 赋值操作的次数是(2nlogn)。 归并算法的空间复杂度为:Θ (n)
Algorithms Lesson 6:Quick sort
算法分析
快速排序使用分治法(Divide and conquer)策略来把一个序列(list)分为两个子序列(sub-lists)。
步骤为:
- 从数列中挑出一个元素,称为 "基准"(pivot),
- 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分割之后,该基准是它的最后位置。这个称为分割(partition)操作。
- 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
递回的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递回下去,但是这个算法总会结束,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。
代码
Algorithms Lesson 7:Heapsort
算法分析
堆积树节点的访问
代码
通常堆积树(heap)是通过一维数组来实现的。在起始阵列为 0 的情形中:
- 堆积树的根节点(即堆积树的最大值)存放在阵列位置 1 的地方;
注意:不使用位置 0,否则左子树永远为 0[2]
- 节点i的左子节点在位置 (2*i);
- 节点i的右子节点在位置 (2*i+1);
- 节点i的父节点在位置 floor(i/2);
堆积树的操作
在堆积树的数据结构中,堆积树中的最大值总是位于根节点。堆积树中定义以下几种操作:
- 最大堆积调整(Max_Heapify):将堆积树的末端子结点作调整,使得子结点永远小于父结点
- 建立最大堆积(Build_Max_Heap):将堆积树所有数据重新排序
- 堆积排序(HeapSort):移除位在第一个数据的根结点,并做最大堆积调整的递归运算
归并操作的工作原理如下:
- 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
- 设定两个指针,最初位置分别为两个已经排序序列的起始位置
- 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
- 重复步骤3直到某一指针达到序列尾
- 将另一序列剩下的所有元素直接复制到合并序列尾
如果目标是把n个元素的序列升序排列,那么采用插入排序存在最好情况和最坏情况。最好情况就是,序列已经是升序排列了,在这种情况下,需要进行的比较操作需(n-1)次即可。最坏情况就是,序列是降序排列,那么此时需要进行的比较共有n(n-1)/2次。插入排序的赋值操作是比较操作的次数减去(n-1)次。平均来说插入排序算法复杂度为O(n2)。因而,插入排序不适合对于数据量比较大的排序应用。但是,如果需要排序的数据量很小,例如,量级小于千,那么插入排序还是一个不错的选择。