排列乘法

假設咱們已有6個元素{a,b,c,d,e,f},咱們要將這6個元素的一個序列改爲另外一個序列算法

  好比:a b c d e f ide

  --->  c d f b e a spa

咱們能夠採用「循環記號」標記上面的改變code

  (acf)(bd)blog

表示爲a-->c,c-->f,f-->a,b-->d,d-->b排序

在一個排列以後咱們又能夠應用另外一個排序,咱們能夠將兩個排列相乘io

| a b c d e f |     | a b c d e f |     | a b c d e f |event

|                  |  * |                 |  = |                  |class

| c d f b e a |     | b d c a f e |     | c a e b f d |cli

顯然排列乘法不知足交換率,採用循環記號,咱們能夠將上面的乘式寫爲:

(acf)(bd)(abd)(ef)=(acefb)

所以咱們能夠處理多項乘式相乘的結果。

循環掃描

算法流程

  E1.將乘法式中的右括號替換爲與之對應的左括號後一個的字符

  E2.從左到右找出沒有被標記過的元素(全部元素都被標記了則算法結束),將該元素賦給Start,輸出左括號以及該元素,並標記該元素

  E3.將當前的算式的後一個元素賦給Current

  E4.向右掃描算式,若是找到Current的元素,則返回E3.不然掃描至算式末尾

  E5.判斷Current==Start,若是不相等,標記Current,找到Current在算式最開始出現的地方.返回E3.

  E6.輸出右括號,返回E2

證實

  針對每個未標記的元素根據算式遍歷找到最終的替換元素,而後標記該元素,顯然能夠找出全部元素最終替換元素,複雜度爲O(N*L)

代碼實現

void ChangeStr(char *str)
{
    int i;
    char pre;
    for(i=0;str[i]!='\0';++i)
    {
        if(str[i]=='(')
        {
            pre=str[i+1];
        }
        if(str[i]==')')
        {
            str[i]=pre;
        }
    }
}
int FindAnyEle(char *src,char *flag,char *start)
{
    int i;
    for(i=0;src[i]!='\0';++i)
    {
        if(src[i]=='(')
        {
            continue;
        }
        if(!flag[src[i]-'a'])
        {    
            *start=src[i];
            printf("(%c",src[i]);
            flag[src[i]-'a']=1;
            return i;
        }
    }
    return -1;
}
int FindNextEle(char *src,char key,int from)
{
    int i;
    for(i=from+1;src[i]!='\0';++i)
    {
        if(src[i]==key)
        {
            return i;
        }
    }
    return -1;
}
int FindOneEle(char *src,char *flag,char key)
{
    int i;
    for(i=0;src[i]!='\0';++i)
    {
        if(src[i]==key)
        {
            printf("%c",key);
            flag[src[i]-'a']=1;
            return i;
        }
    }
    return -1;
}
void PermutationMul(int EleNum,char *SrcMulStr)
{
    ChangeStr(SrcMulStr);
    char *Flag=(char *)malloc(EleNum*sizeof(char));
    int i,id;
    char Start,Current;
    for(i=0;i<EleNum;++i)
    {
        Flag[i]=0;
    }
    id=FindAnyEle(SrcMulStr,Flag,&Start);
    while(~id)
    {
        while(~id)
        {
            Current=SrcMulStr[id+1];
            id=FindNextEle(SrcMulStr,Current,id+1);
        }
        if(Current!=Start)
        {
            id=FindOneEle(SrcMulStr,Flag,Current);
        }
        else
        {
            printf(")");
            id=FindAnyEle(SrcMulStr,Flag,&Start);
        }
    }
    free(Flag);
    printf("\n");
}
View Code

逆序迭代

算法流程

  E1.初始化,對於1<=i<=N,將T[i]=i;T[i]表示i元素將被T[i]元素替換

  E2.從右往左讀取輸入算式,讀取下一個元素,若是輸入結束,算法則也結束,若是元素爲')',置Z=0重複E2;若是爲‘(’,轉去E4,不然轉到E3

  E3.交換Z與T[i],若是此時T[i]==0,將i賦值給j;返回E2

  E4.將T[j]賦爲Z;返回E2

證實

  一遍掃描迭代更新T[i]最終被替換的值,由於咱們要找到最終被替換的值,因此要從右往左讀,若是從左往右讀能夠迭代求出最終替換項被替換的值,好比最終T[1]=3,從右往左讀的話,表示最終1要被3代替,從左往右讀的話,表示最終3是被1代替.

  顯然經過逆序迭代每對括號,更新每對括號包含的替換信息,最終能夠求出每一個元素被替代的值,複雜度爲O(L)

代碼實現

void PermutationMulEx(int EleNum,char *SrcMulStr)
{
    int i,j,Z,Len,t;
    char *T=(char *)malloc(EleNum*sizeof(char));
    for(i=0;i<EleNum;++i)
    {
        T[i]=i;
    }
    Len=strlen(SrcMulStr);
    for(i=Len-1;i>=0;--i)
    {
        if(SrcMulStr[i]==')')
        {
            Z=-1;
            continue;
        }
        if(SrcMulStr[i]=='(')
        {
            T[j]=Z;
        }
        else
        {
            t=Z;
            Z=T[SrcMulStr[i]-'a'];
            T[SrcMulStr[i]-'a']=t;
            if(T[SrcMulStr[i]-'a']==-1)
            {
                j=SrcMulStr[i]-'a';
            }
        }
    }
    for(i=0;i<EleNum;++i)
    {
        printf("%d ",T[i]);
    }
    printf("\n");
    free(T);
}
View Code
相關文章
相關標籤/搜索