第六章 堆排序
二叉堆数据结构是一种数组对象。
堆排序思想:首先建立一个最大堆函数,得到第一个节点是堆的最大值,将第一个节点与最后一个节点互换,将堆的大少减一,循环调用,即得到一个从大到小的序列。
堆排序代码:
w-s Max-heapify(A,i) //子节点和父节点排序 O(lg(n)) { l = left(i) r = right(i) if l <= heap-size[A] && A[l] > A[i] then largest = l else largest = i if r <= heap-size[A] && A[r] > A[largest] then largest = r if largest != i then exchange A[i] <-> A[largest] Max-heapify(A,largest) } Build-max-heap(A) //建立完整的堆 O(n) { heap-size[A] = length[A] for i = (length[A]/2) downto 1 //只需要将堆里面倒数第二排最后一个有子节点的点开始建立最大堆 do Max-heapify(A,i) } /*堆排序算法*/ Heapsort(A) //对堆进行排序 { Build-max-heap(A) O(n) for i = length[A] downto 2 do exchange A[1] <-> A[i] heap-size[A] = heap-size[A]-1 Max-heapify(A,1) O(nlg(n)) }
优先队列(堆排序的一种应用):
/*
优先级队列支持操作:
Heap-maxinum(S)
Max-heap-Inser(S,x)
Heap-Extract-max(S) 去掉并返回S中具有最大关键字的元素
Heap-Increase-key(S,x,k) 将元素x的关键字的值增加到k,这里k不能小于x的原关键字
*/
// 堆里面最大值 w-s Heap-maximum(A) O(1) return A[1] //插入x到堆里面 Max-heap-inset(A,key) O(lg(n)) { heap-size[A] = heap-size[A]-1 A[heap-size[A]] = -∞ Heap-Increase-key(A,heap-size[A],key) } //去掉并返回S中最大关键字的元素 Heap-Extract-max(A) O(lg(n)) { if heap-size[A] < 1 then error"heap underflow" max = A[1] A[1] = A[heap-size[A]] heap-size[A] = heap-size[A]-1 Max-heapify(A,1) return max } //将元素x的关键字加到k中 Heap-Increase-key(A,i,key) O(lg(n)) { if key < A[i] then error"new key is smaller than current key" A[i] = key while i > 1 && A[parent(i)] < A[i] do exchange A[i] <-> A[parent(i)] i = parent(i) }
//快速排序的解决式 w-s a-s b-s Quick-sort(A,p,r) T(n)= T(n-1)+cn O(nlg(n)) O(nlg(n)) { if p < r then q = Partition(A,p,r) Quick-sort(A,p,q-1) Quick-sort(A,q+1,r) } //快速排序的分解 Partition(A,p,r) { x = A[r] i = p-1 for j = p to r-1 do if A[j] <= x then i = i+1 exchange A[i] <-> A[j] exchange A[i+1] <-> A[r] return i+1 }
Randomized-partition(A,p,r) { i = random(p,r)//在A中随机抽取一个值i exchange A[r] <-> A[i] return partition(A,p,r) } Random-quicksort(A,p,r) { if p < r then q = randomized-partition(A,p,r) Random-quicksort(A,p,q-1) Random-quicksort(A,q+1,r) }
Stooge-sort(A,i,j) { if A[i] > A[j] then exchange A[i] <-> A[j] if i +1 >= j then return k = (j-i+1)/3 //round down stooge-sort(A,i,j-k) //first two-thirds stooge-sort(A,i+k,j) //last two-thirds stooge-sort(A,i,j-k) //first two-thirds again }
决策树模型(比较排序)
计数排序
思想:创建一个length(A)大小的数组B,和一个辅助数组C,辅助数组用来计数数组里面相同数的个数和位置,然后将辅助数组的书位置,即排好书序的下标赋给数组B的下表,将数组A对应的数赋给B的值。
Counting-sort(A,B,k) w-s { for i = 0 to k O(n) do C[i] =0 for j = 1 to length[A] O(n) do C[A[j]] = C[A[j]] +1 for i =1 to k O(n) do C[i] = C[i] + C[i-1] for j = length[A] downto 1 O(n) do B[C[A[j]]] e= A[j] C[A[j]] = C[A[j]] -1 }复杂度:T(n) = O(n)
计数排序:
思想:首先将数进行分类,得出其位数,然后通过低位进行排序,直到最高位排序,最终得出排好的序列
Radix-sort(A,d) { for i = 1 to d do use a stable sort to sort array A on digit i }
桶排序
思想:创建一个length(A) 的数组,并且元素满足 0<= A[i] =< 1,通过十分位,百分位的数作为下标放入桶B里面,十分位相同,可通过创建链表的方式来比较百分位的位置,依次类推。
Bucket-sort(A) w-s { n = length[A] for i = 1 to n O(n) do inset A[i] into list B[nA[i]] for i = 0 to n-1 O(n) do sort list B[i] with insertion sort concatenate the lists B[0] ,B[1].....B[n] together in order }
第九章 中位数和顺序统计学
最大值和最小值
以期望线性时间做选择
如果我们不选最大值或最小值,而是选一个第i小的值。我们可以用一种分治算法——RAMDOMIZED_SELECT,它以快速排序为模型:把数组随机划分为两部分,A[p...q-1]的元素比A[q]小,A[q+1...r]的元素比A[q]大。与快速排序不同,如果i=q,则A[q]就是要找的第i小的元素,返回这个值;如果i < q,则说明第i小的元素在A[p...q-1]里;如果i > q,则说明第i小的元素在A[q+1...r]里。
RANDOMIZED_SELECT(A, p, r, i) { 1 if p == r 2 return A[p]; 3 q = RANDOMIZED_PARTITION(A, p, r); 4 k = q-p+1; 5 if i == k 6 return A[q]; 7 elseif i < k 8 return RANDOMIZED_SELECT(A, p, q-1, i); 9 else return RANDOMIZED_SELECT(A, q+1, r, i-k); }
用代换法解上式,可以得到E(T(n))=O(n)。也就是说在平均情况下,任何顺序统计量(特别是中位数)都可以在线性时间内得到。
最坏情况线性时间的选择
首先我们需要稍微修改一下PARTITION算法(不是RANDOMIZED_PARTITION),它接收一个数组和一个值x,并把它划分为小于x和大于x的两部分(x为A中某个元素的值):
PARTITION_X(A, p, r, x) { 1 for i = 1 to n 2 if A[i] == x { 3 swap(A[i], A[n-1]); 4 break; 5 } 6 return PARTITION(A, p, r); }
SELECT(A, p, r, i) { // 步骤1、2 1 count = ceiling(n/5); 2 for i = 1 to count-1 3 insertion sort A[(i-1)*5+1...i*5+1]; 4 insertion sort A[(count-1)*5+1...n]; 5 if count ==1 6 return A[floor(n/2)]; // 步骤3 7 create array B; 9 for i = 1 to count-1 10 B[i] = A[(i-1)*5+3]; 11 B[count] = A[(count-1)*5 + floor((n - (count-1)*5)/2)]; 12 x = SELECT(B, 1, count, floor(count/2)); // 步骤4 13 q = PARTITION_X(A, p, r, i); 14 k = q-p+1; // 步骤5 15 if i == k 16 return x; 17 elseif i < k 18 return SELECT(A, p, q-1, i); 19 else 20 return SELECT(A, q+1, r, i-k); }