侧重于分解:快速排序、次序选择
侧重于合并:归并排序、逆序计数、最大子数组
最大子数组问题
GetAcross(A, left, mid, right)
{
// mid左边
s_left = -INF, sum = 0;
for(i=mid to left) {
sum += A[i];
if (sum > s_left) {
s_left = sum;
}
}
// mid右边
s_right = -INF, sum =0;
for (i=mid+1 to right) {
sum += A[i];
if (sum > s_right) {
s_right = sum;
}
}
return (s_left + s_right);
}
MNC(A, left, right)
{
if (left >= right) return A[left];
else {
mid = (left + right)/2;
s1 = MNC(A, left, mid);
s2 = MNC(A, mid+1, right);
s3 = GetAcross(A, left, mid, right);
return max(s1, s2, s3);
}
}
归并排序问题
Merge(A, left, mid, right)
{
B[left..right] = A[left..right];
k = 0;
i = left, j = mid+1;
while(i<=mid and j<=right) {
if(B[i] <= B[j]) {
A[k] = B[i];
k++, i++;
}
else {
A[k] = B[j];
k++, j++;
}
}
while (i <= mid) {
A[k..right] = B[i..mid];
}
while (j <= right) {
A[k..right] = B[j..right];
}
return A[left..right];
}
MergeSort(A, left, right)
{
if(left >= right) return A[left]
else {
mid = (left + right)/2;
MergeSort(A, left, mid); // T(n/2)
MergeSort(A, mid+1, right); // T(n/2)
Merge(A, left, mid, right); // O(n)
return A[left..right];
}
}
逆序计数问题
Merge(A, left, mid, right)
{
B[left..right] = A[left..right];
k = 0;
i = left, j = mid+1;
s3 = 0;
while(i<=mid and j<=right) {
if(B[i] <= B[j]) {
A[k] = B[i];
k++, i++;
}
else {
A[k] = B[j];
k++, j++;
s3 += mid-i+1; // 如果B[i] > B[j], 那么B[i..mid] > B[j]
}
}
while (i <= mid) {
A[k..right] = B[i..mid];
}
while (j <= right) {
A[k..right] = B[j..right];
}
return A[left..right];
}
MergeCount(A, left, right)
{
if(left >= right) return 0,A[left]
else {
mid = (left + right)/2;
s1 = MergeCount(A, left, mid); // T(n/2)
s2 = MergeCount(A, mid+1, right); // T(n/2)
s3 = Merge(A, left, mid, right); // O(n)
return (s1+s2+s3), A[left..right];
}
}
快速排序算法
Partation(A, p, r)
{
x = A[r]; // 选取固定主元
i = p - 1;
for (j=p to r-1) {
if (A[j] <= x) {
exchange(A[i+1], A[j]);
i = i+1;
}
}
exchange(A[r], A[i+1]); // 把主元放到中间
return i+1;
}
QuickSort(A, p, r)
{
if (p < r) {
q = Partation(A, p, r);
QuickSort(A, p, q);
QuickSort(A, q+1, r);
}
}
时间复杂度为(O(n^2))
随机化选取主元
Randomized-Partation(A, p, r)
{
k = random(p,r)
x = A[k];
exchange(A[k], A[r]);
//
i = p - 1;
for (j=p to r-1) {
if (A[j] <= x) {
exchange(A[i+1], A[j]);
i = i+1;
}
}
exchange(A[r], A[i+1]); // 把主元放到中间
return i+1;
}
Randomized-QuickSort(A, p, r) {
if (p < r) {
q = Randomized-Partation(A, p, r);
Randomized-QuickSort(A, p, q);
Randomized-QuickSort(A, q+1, r);
}
}
时间复杂度为(O(nlogn))
次序选择
找一个数组中第k小的元素
思路一:将整个数组排序((O(nlogn))), 然后直接选取下标为left+k-1的元素即可
思路二:根据快速排序数组划分的思想,每次选取一个主元,然后把数组划分成左右两边,判断k 和 q-p+1的大小关系
SelectionProblem(A, left, right)
{
q = Randomized-Partation(A, left, right); //主要是使用了随机化快速排序,降低了时间复杂度
if (k == q-p+1){
return A[q];
}
else if (k < q-p+1) {
return SelectionProblem(A, left, q-1);
}
else {
return SelectionProblem(A, q+1, right);
}
}
时间复杂度是(O(n))
基于比较的排序算法时间复杂度的下限是(O(nlogn))