排列乘法

假设咱们已有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
相关文章
相关标签/搜索