zoukankan      html  css  js  c++  java
  • 算法导论76 对区间的模糊排序

    【转】

    《算法导论》chapter7 problem7-6对区间的模糊排序

      考虑这样一种排序问题,即无法准确的知道等排序的各个数字到底 是多大.对于其中的每个数字,我们只知道它落在实轴上的某个区间内.亦即,给定的 n 个形如[ai, bi ]的闭区间,其中ai,≤bi .算法的目标是对这些区间进行模糊排序(fuzzy-sort),亦即,产生各区间的一个排序<i1, i2, i3, i4,…in >,使得存在一个 cj ∈[ai, bi ],满足c1≤c2≤…≤cn .

      a)为n个区间的模糊排序设计一个算法,你的算法应该具有算法的一般结构,它可以快速排序左部端点(即各ai ),也要能充分利用重叠区间来改善运行时间.(随着各区间重叠得越来越多,对各区间的排序的问题会变得越来越容易,你的算法应该能充分利用这种重叠.)

      b)证明: 在一般情况下,你的算法的区望运行时间为 O(n*lgn),但当所有的区间都重叠时,期望的运行时间为O(n) (亦即,当存在一个值 x, 使得对所有的 i, 都有x∈[ai, bi ] ).你的算法不应显式的检查这种情况,而是应当随着重叠量的增加,性能自然地有所改善.

        解答

       a.  算法思想基本是仿快速排序对区间进行排序。难点在于如何充分利用重叠区间来改善运行时间?其关键在于Partion()的设计。

       对于如何充分利用重叠区间,解决思路是在调用Partion()划分时,区间如果重叠的部分,就把它们看做是相等的,并提取公共部分继续划分。即对于区间[ai,bi],[aj,bj],它们大小分为三种情况。

       if(bi<aj)那么[ai,bi]<[aj,bj]

       else if(bj<ai)那么[aj,bj]<[ai,bi]

       else [ai,bi]=[aj,bj]。

       网上其它人的解答,思路都是类似的,不过看了几个版本,不少人在代码实现上多少有点bug。一个易错的地方是在判定两个区间相等的情况后,要提取它们公共区域继续划分。另一个错误有点难描述,以下面的代码为例,在else if(interArr[k].a>midInterval.b){}里面, 没有加上“k--”这一行代码。至于什么要加一行代码,因为在interArr[k]比基准midInterval大而需要Exchange时,和 interArr[j]交换时,interArr[j]也可能比基准midInter大的。我们如果不k--,那么就会直接跳过去了。这样说如果有点模糊 的话,可以拿下面数据模拟一次就明白了。

    28508 31359

    4712 30466

    23267 30245

    7134 8098

    25400 26351

    8079 29052

    31163 31738

    6346 24352

      具体代码如下

    #include <iostream>

    #include
    <ctime>

    using namespace std;

    struct IntervalType

    {

    int a;

    int b;

    };

    void Exchange(IntervalType interArry[],int i,int j)

    {

    IntervalType tmpInterval
    =interArry[i];

    interArry[i]
    =interArry[j];

    interArry[j]
    =tmpInterval;

    return ;

    }

    //将区间[oBeg,oEnd]以某区间为基准,分成[oBeg,preEnd]<[preEnd+1,postBeg-1]<[postBeg,oEnd]三个区间

    void Partition(IntervalType interArr[],int oBeg,int oEnd,int &preEnd,int &postBeg)

    {

    IntervalType midInterval
    =interArr[oEnd];

    int i=oBeg-1;

    int j=oEnd+1;

    for(int k=oBeg;k<j&&k<oEnd;k++)

    {

    if(interArr[k].b<midInterval.a)//区间k比基准区间小

    {

    i
    ++;

    Exchange(interArr,k,i);

    }

    else if(interArr[k].a>midInterval.b)//区间k比基准区间大

    {

    j
    --;

    Exchange(interArr,k,j);

    k
    --;

    }

    else//两个区间有重叠,视作相等,取它们重叠的部分作为基准区间继续划分

    {

    midInterval.a
    =max(midInterval.a,interArr[k].a);

    midInterval.b
    =min(midInterval.b,interArr[k].b);

    }

    }

    preEnd
    =i;

    postBeg
    =j;

    return;

    }

    void IntervalQuickSort(IntervalType interArr[],int iBeg,int iEnd)

    {

    if(iBeg>=iEnd)return;

    int preEnd,postBeg;

    //将区间[iBeg,iEnd]以某区间为基准,分成[iBeg,preEnd]<[preEnd+1,postBeg-1]< [postBeg,iEnd]三个区
    Partition(interArr,iBeg,iEnd,preEnd,postBeg);


    IntervalQuickSort(interArr,iBeg,preEnd);

    IntervalQuickSort(interArr,postBeg,iEnd);

    return ;

    }

    //输出存在的符合题意的排列,同时判断我们对区间的排序结果是否正确,即是否能找到这样一个满足条件的排列。

    bool PrintExitCArray(IntervalType interArray[],int n)

    {

    int* c=new int[n];

    cout
    <<interArray[0].a<<" ";

    c[
    0]=interArray[0].a;

    for(int i=1;i<n;i++)

    {

    c[i]
    =max(c[i-1],interArray[i].a);

    if(c[i]>interArray[i].b)

    {

    cout
    <<"error!/n";

    return false;

    }

    cout
    <<c[i]<<" ";

    }

    return true;

    }

    int main()

    {

    srand((unsigned)time(
    0));

    IntervalType interArray[
    10000];

    int n=0;

    cout
    <<"输入区间个数n:";

    cin
    >>n;

    cout
    <<"下面随机输入"<<n<<"个区间的起点终点a,b:"<<endl;

    for(int i=0;i<n;i++)

    {

    interArray[i].a
    =rand()%1000;

    interArray[i].b
    =rand()%1000;

    while(interArray[i].a>interArray[i].b)

    {

    interArray[i].b
    =rand()%1000;

    }

    cout
    <<interArray[i].a<<" "<<interArray[i].b<<endl;

    }

    IntervalQuickSort(interArray,
    0,n-1);

    cout
    <<"模糊排序的结果如下:"<<endl;

    for(int i=0;i<n;i++)

    cout
    <<interArray[i].a<<" "<<interArray[i].b<<endl;

    cout
    <<"可能存在的排列如下:"<<endl;

    if(PrintExitCArray(interArray,n))

    {

    cout
    <<endl<<"成功找到一个满足条件的排列。"<<endl;

    }

    else

    {

    cout
    <<"算法失败,存在bug。"<<endl;

    }

    return 0;

    }


       大家如果有自己的实现版本,可以参考上面随机生成几百个数据,用函数bool PrintExitCArray(IntervalType interArray[],int n)来测试下自己写的代码是否正确。

  • 相关阅读:
    [转载]读史札记21:出局依然是英雄
    关于 Delphi 中窗体的停靠
    关于 Indy 的发送与接收 及 不定长度流的见解
    基于Indy10 ,TCPIP 聊天示例
    opera 去除标题栏,最大化窗口代码
    第二篇 《XML 类化生成工具》
    第一篇《后缀表达式》
    多线程操作一例:查找 pas dfm 里的中文
    关于批量执行SQL语句
    Erlang 学习笔记 (一)
  • 原文地址:https://www.cnblogs.com/longdouhzt/p/2107848.html
Copyright © 2011-2022 走看看