数据结构:
在实际中, 待排序的数很少是单独的数值, 他们通常是称为记录(record)的数据集的一部分.每个记录包含一个关键字(key),就是排序问题中要重排的值.记录的剩余部分由卫星数据(satelite data)组成,通常与关键字是一同存取的.在实际中,当一个排序算法重排关键字时, 也必须要重排卫星数据.如果每个记录包含大量的卫星数据, 我们通常重排记录指针的数组,二不是记录本身,这样可以降低数据的移动量.
在某种意义上,正是这些实现细节将一个算法与成熟的程序区分开来.一个排序算法描述确定有序次序的方法(method), 而不管我们是在排序单独的数还是包含很多卫星数据的大记录.因此,当面对排序问题时, 我们通常假定输入只是由数组成.将一个对数进行排序的算法转换成一个对记录进行排序的程序在概念上是很直接的.当然在具体的工作情景下,其他一些细节问题可能会使实际的编程工作遇到很多挑战.
为什么要排序
很多计算机科学家认为排序是算法研究中最基础的问题.其原因有很多
有时应用本身就需要对信息进行排序.
很多算法通常把排序作为关键子程序..例如在一个渲染图形对象的程序中,图形对象是分层叠在一起的,这个程序可能就需要按上层关系来排序对象.一遍能按自底向上的次序绘制对象..
插入排序由于内层循环非常紧凑,对于小规模输入,插入排序是一种非常快的原址排序算法.(回忆一下,如果输入数组中仅有常数个元素需要在排序过程中存储在数组之外,则称排序算法是原址的(in place)))
插入排序,归并排序,堆排序以及快速排序都是比较排序算法:他们都是通过对元素进行比较操作来确定输入数组的有序次序
堆排序不同归并排序的是,堆排序同样具有控件原址性:任何时候都只需要常数个额外的元素空间存储临时数据
对应堆排序,给定一个结点的下标i, 我们很容易计算得到它的上节点,左结点和右结点的下标。
任意i, parent: return i/2Left : return 2*i Right:return 2*i+1;
MAX-HEAPIFY(A, i)
l = LEFT(i)
R = RIGHT(i)
If l <= A.heap.size and A[i] > A[l]
Largest = l;
Else largest = i;
If r <= A.heap.size and A[r] > A[largest]
Largest = r;
If largest ≠ i
Exchange A[i] with A[largest]
MAX-HEAPIFY(A, largest);
MAX-HEAPIFY的执行过程即是:自顶向下的对无序堆进行调整。在程序的每一步中,从A[i]、A[LEFT], A[Right]中选出最大的,并将其下标存储在largest中。如果A[i]是最大的,那么以i为节点的子树已经是最大值,程序结束。否则,最大元素是i的某个子节点,则交换A[i]和A[largest]的值。从而使i以及子节点满足最大堆的性质,在交换后,下标为largest结点的值是原来的A[i], 于是以该点为根的子树又有可能会违反最大堆的性质,因此,需要对该子树递归调用MAX-HEAPIFY.
对于一颗以i为根节点,大小为n的子树,MAX-HEAPIFY的时间代价包括:调整A[i]和A[left(i)], A[Right(i)]的关系的时间代价o(1),加上在一颗以i的一个孩子为根节点的子树上运行MAX-HEAPIFY的时间代价,这里假设递归调用会发生。
建堆:
我们可以用自底向上的方法利用过程MAX-HEAPIFY把一个大小为n = A,length的数组A[1..n]转换为最大堆。通过基础可以知道,子数组A([n/2+1]... n)中的元素都是树的叶结点。每个叶结点都可以看作只包含一个元素的堆。过程BULID-MAX-HEAP对树中的其他节点都调用一次MAX-HEAPIFY。
BUILD-MAX-HEAP(A)
A.heap.size = A.length
For i = [A.length/2] downto 1
MAX-HEAPIFY(A, i)\\
类似的,我们也可以通过调用BUILD-MIN-HEAP构造一个最小堆。除了第三行的调用替换为MIN-HEAPIFY外,其他不变。
堆排序算法
初始时候,堆排序算法利用BUILD-MAX-HEAP将输入数组A[1....n]建成最大堆,其中n = A.length。因为数组中的最大元素总在根节点A[1]中, 通过把它与A[n]进行互换,我们可以让该元素放到正确的位置。这时候,如果我们从堆中去掉节点n(这一个操作可以通过减少A.heap.size的值来实现), 剩余的节点中,原来根的孩子节点仍然是最大堆,而新的根节点可能会违背最大堆的性质。为了维护最大堆的性质,我们要做的是调用MAX-HEAPIFY(A,1),从而在A[1......n-1]上构造一个新的最大堆。堆排序算法会不断重复这一个过程,直到堆的大小从n-1降到2.
HEAPSORT(A)
BUILD-MAX-HEAP(A)
For i = A.length downto 2
Exchange A[1] with A[i]
A.heap.size = A.heap.size - 1
MAX-HEAPIFY(A, 1)
堆排序算法大致流程: 构建最大堆, 逐渐减小堆大小并取出最大元素并同时维护最大堆