演算法導論7.6對區間的模糊排序

來源:互聯網
上載者:User

題目:

7-6 對區間的模糊排序

    考慮這樣的一種排序問題,即無法準確地知道待排序的各個數字到底是多少。對於其中的每個數字,我們只知道它落在實軸上的某個區間。亦即,給定的是n個形如[ai,bi]的閉區間,其中ai≤bi。演算法的目標是對這些區間進行模糊排序(fuzzy-sort),亦即,產生的各區間的一個排列<i1,i2,...,in>,使得存在一個cj∈[ai, bi],滿足c1≤c2≤...≤cn。

a)為n個區間的模糊排序設計一個演算法。你的演算法應該具有演算法的一般結構,它可以快速排序左部端點(即各ai),也要能充分利用重疊區間來改善已耗用時間。(隨著各區間重疊得越來越多,對各個區間進行模糊排序的問題會變得越來越容易。你的演算法應能充分利用這種重疊。)

b)證明:在一般情況下,你的演算法的期望已耗用時間為Θ(nlgn),但當所有的區間都重疊時,期望的已耗用時間為Θ(n)(亦即,當存在一個值x,使得對所有的i,都有x∈[ai,bi])。你的演算法不應顯示地檢查這種情況,而是應當隨著重疊量的增加,效能自然地有所改善。

思路:剛開始看到這個題目,整了半天沒整明白是個什麼回事,後來通過例子終於自我認為理解了。要理解上面所說的區間模糊排序。首先要點是,這是區間排序,即和快速排序不同,快速排序是每一個元素都是確定的,而這裡每一個元素都是一段區間,排序結果也是不一定正確的,即是模糊的。要先理解下面的一個偏序關係  先思考一個問題:為什麼區間重疊能改善排序演算法的期望已耗用時間呢?想明白了其實很簡單,這相當於我們用快速排序一個數組時,數組中有很多重複元素,如果我們做一個改進,將劃分從2部分變成3部分,前邊部分是小於,中間是等於,後面是大於。那麼以後每次需要劃分的區間(只劃分小於和大於)都可能會大大減小,這樣PARTITION時就可能非常高效。

a)首先定義兩個線段的偏序關係(非唯一),如所示

以線段i的左端點ai為參照物,分為三種情況:

1)線段j<線段i, 此時滿足b.end<a.begin

2)線段j=線段i, 此時滿足b.begin≤a.begin≤b.end。這樣定義的原因是:最後可以讓線段j和線段i的ci均取a.begin(重疊部分)

3)線段j>線段i, 此時滿足b.begin>a.begin

通過我們可以清晰地感性地認知偏序小於,偏序大於,偏序等於各屬於什麼情況。圖真是一個好東西

思考很久,我終於發現區間模糊排序本質上是快排的一種變種。區間排序實質上是以區間為單位進行操作,所以,需要定義一個結構體儲存區間首尾元素。而快排是以元素為單位排序。通過定義偏序大於,小於和等於關係,再對快排的partition做了一點改進,使它每次都可以返回一個區間結構體,使得左邊的小於,右邊的大於,中間的等於。代碼:

#include<iostream>#include<ctime>using namespace std;//模糊排序的輸入是一個區間數值對,所以定義一個結構體struct node{int a;int b;};//交換兩個結構體void swap(node& a,node& b){node temp=a;a=b;b=temp;}//劃分成三段的partition函數,最左邊是小於主元,最右邊是大於主元,中間是等於主元的//將區間[l,r]以某區間為基準,分成[l,i]<[i+1,j-1]<[j,r]三個區間node partition(node a[],int l,int r){//選最後一個元素為主元,ret為儲存劃分點的結構體node x=a[r],ret;int i=l-1;//跟蹤小區間int j=r+1;//跟蹤大區間int k=l;//遍曆整個數組while(k<j && k<=r){if(a[k].b<x.a)//如果小於主元,交換到前面  {++i;swap(a[i],a[k]);++k;}else if(a[k].a>x.a) ////如果大於,交換到後面  {j--;swap(a[j],a[k]);//這裡不能k++,因為交換過來的元素也可能大於主元  }else {//兩個區間有重疊,視作相等,取它們重疊的部分作為基準區間繼續劃分,一開始基準區間比較大,劃分到後面,基準區間漸漸層小//劃分到最後的結果就是[i,j],則i的左邊是小區間,j的後邊是大區間,而[i,j]是剩餘區間重疊的部分,即相等的部分//本質上是快速排序的變種,快排是每調用partition一次,可以確定一個樞點,使其左邊的數小於樞點,右邊的數大於樞點//而這個每調用partition一次,可以確定一個“相等”區間,使其左邊的都小於(偏序意義上)樞點區間,右邊大於樞點區間//快排可以確定一個準確序列,而模糊化排序可以確定一個可能的區間排序x.a=max(a[k].a,x.a);x.b=min(a[k].b,x.b); //如果相等,不交換,但是要提取公因子++k;}}ret.a=i;ret.b=j;return ret;//ret暫存作用}void Fuzzy_sort(node a[],int l,int r){if(l<r){node mid=partition(a,l,r);//mid儲存分割點[i,j]//中間重疊部分不處理,只處理兩頭部分Fuzzy_sort(a,l,mid.a);Fuzzy_sort(a,mid.b,r);}}bool print_possible_sort(node a[],int n){int* c=new int[n];c[0]=a[0].a;cout<<c[0]<<' ';for(int i=1;i<n;i++){c[i]=max(a[i].a,c[i-1]);if(c[i]>a[i].b)//出錯的情況為第i個區間比第i+1個區間大,即i.a>(i+1).b{cout<<"error!"<<endl;return false;}cout<<c[i]<<' ';}delete []c;return true;}int main(){srand((unsigned)time(0));node a[10000];int n=0;cout<<"輸入區間個數n:";cin>>n;cout<<"下面隨機輸入"<<n<<"個區間的起點終點a,b:"<<endl;for(int i=0;i<n;i++)//產生有效區間對{a[i].a=rand()%1000;a[i].b=rand()%1000;if(a[i].a>a[i].b){swap(a[i].b,a[i].a);}cout<<a[i].a<<" "<<a[i].b<<endl;}Fuzzy_sort(a,0,n-1);cout<<"模糊排序的結果如下:"<<endl;for(int i=0;i<n;i++)cout<<a[i].a<<" "<<a[i].b<<endl;cout<<"可能存在的排列如下:"<<endl;if(print_possible_sort(a,n)){cout<<endl<<"成功找到一個滿足條件的排列。"<<endl;}else{cout<<"演算法失敗!"<<endl;}return 0;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.