对区间的模糊排序(原题算法导论第三版思考题7-6)

题目:
考虑这样一种排序问题,我们无法知道准确待排序的数字是什么。但对于每一个数,我们知道它属于实数轴上的某个区间。也就是说,我们得到了n个形如[ ai,bi ]的封闭区间,其中 aibi 。我们的目标是实现这些区间的模糊排序,即对j=1,2,…,n生成一个区间的排列< i1,i2,...,in >,且存在 cj[aij,bij] ,满足 c1c2...cn
解答:
对于该问题的说明,笔者看了知乎上的一篇回答一篇CSDN上的博客才弄懂题目的意思。
算法导论上的原题提到“你的算法应该有算法的一般结构,它可以对左边端点(即 ai 的值)进行快速排序,同时它也能利用区间的重叠性质来改善时间性能。(当区间重叠越来越多时,区间的模糊排序问题会变得越来越容易。你的算法应该充分利用到这一重叠性质。)”
对于该题,可以利用针对相同元素的快速排序中的思想,将某些重叠的区间归为相等,即针对相同元素的快速排序中的中间部分[q…t],由此来改善该算法的时间性能,使区间重叠越多,模糊排序越容易。该算法的PARTITION同样返回两个值如之前的针对相同元素的快速排序中的PARTITION。
现在我们来定义哪种某些重叠的区间可以归为相等的区间。我们用如下结构体表示区间:

typedef struct interval {
    int start;
    int end;
} interval_t;

对于两个interval_t的a和pivot,如果:
1. a.end<pivot.start ,则判断a区间小于被选为主元的区间。
2. a.startpivot.starta.end ,则判断a区间与主元区间相等。(因为c可以取共同的区间中的值)
3. a.start>pivot.start ,则判断a区间大于主元区间。(即使 pivot.enda.startpivot.start 也不可取其与主元区间相等,或另设一返回区间表示该种可能性)
算法实现如下:

void swap_interval(interval_t *p1, interval_t *p2) {
    interval_t temp = *p1;
    *p1 = *p2;
    *p2 = temp;
}
int comp_interval(interval_t a, interval_t pivot) {
    if (a.end < pivot.start) {
        return -1;
    } else if (a.start <= pivot.start && pivot.start <= a.end) {
        return 0;
    } else if (a.start > pivot.start) {
        return 1;
    } else {
        fprintf(stderr, "error code\n");
        return  404;
    }
}
interval_t interval_partitoin(interval_t *source, int head, int tail) {
    swap_interval(source + rand() % (tail - head + 1) + head, source + tail);
    interval_t pivot = source[tail];
    int q = head - 1, t = head - 1;
    int j = head;
    for (j = head; j < tail; j++) {
        int comp_result = comp_interval(source[j], pivot);
        if (comp_result == 0) {
            t++;
            swap_interval(source + j, source + t);
        } else if (comp_result == -1) {
            q++;
            swap_interval(source + j, source + q);
            t++;
            if (t != q)
                swap_interval(source + j, source + t);
        }
    }
    q++;
    swap_interval(source + tail, source + q);
    t++;
    if (q != t)
         swap_interval(source + tail, source + t);
    interval_t result = {q, t};
    return result;
}
void fuzzy_quick_sort_for_interval(interval_t *source, int head, int tail) {
    if (head >= tail)
        return;
    interval_t mid = interval_partitoin(source, head, tail);
    fuzzy_quick_sort_for_interval(source, head, mid.start - 1);
    fuzzy_quick_sort_for_interval(source, mid.end + 1, tail);
}

代码未经测试,与针对相同元素的快速排序相比只是改了判断大小的逻辑comp_interval和交换的逻辑swap_interval。

猜你喜欢

转载自blog.csdn.net/sinat_16709955/article/details/77193655