邻位互换法

本算法的思想也是希望以(12…n)
作为n个元素1,2,…,n的第一个排列,
然后按照某种方法,
由一个排列(p)=(p1p2…pn)直接生成下一个排列,
直到全部排列生成完毕为止。
以n=4为例,开始在排列1234的各数上方加一个左箭头“←”,
当一个数上方箭头所指的一侧,相邻的数比该数小时,
便称该数处于活动状态。
从排列(p)=(p1p2…pn)生成下一个排列的算法如下:
(1)若排列(p)=(p1p2…pn)中无一数处于活动状态,则停止,
否则转(2);
(2)求所有处于活动状态的数中的最大者,设为k,
k和它的箭头所指的一侧的相邻数互换位置,转(3);
(3)令比k大的所有数的箭头改变方向,转(1)。

算法如下:

请自行调试

*/
#include <iostream>
using namespace std;
enum DIR{LEFT=-1,RIGHT=1};

函数功能:判断下标i所指p中元素是否处于活动状态
输入参数:p  ,指向n个字符的一个当前排列
        dir ,标记p中每个元素的箭头方向
        i   ,待判定元素的下标
        N   ,待排列字符的个数
 返回值:   true 表示待判定元素为活动状态,
        false 表示待判定元素处于非活动状态
bool IsActive(const char *p,const DIR *dir,const int i,const int N)
{
    if(i+dir[i] < 0 || i+dir[i] >= N)return false;
    if(p[i+dir[i]] < p[i])  //箭头所指一侧相邻的数比该数小
        return true;
    else return false;
}

函数功能:找到p中处于活动状态的数中的最大者
输入参数:p  ,指向n个字符的一个当前排列
        dir ,标记p中每个元素的箭头方向
        N   ,待排列字符的个数
返回值:上述最大者的下标,-1表示调用参数有误,N表示没有活动者
int MaxActive(const char *p,const DIR *dir,const int N)
{
    int k=N;
    for(int i=0;i<N;i++)
        if(IsActive(p,dir,i,N) && (p[i] > p[k]))
            k = i;
    return k;
}

函数功能:交换下标i所指元素与其箭头方向所指元素,原位交换
输入参数:p  ,指向n个字符的一个当前排列
        dir ,标记p中每个元素的箭头方向
        i   ,待交换元素的下标
返回值:    true 表示交换成功
        false 表示交换失败,失败原因为调用参数有误。
bool Swap(char *p, DIR *dir, int *i)
{
    if(p == NULL || dir == NULL)return false;
    //交换相邻的元素;
    char temp = p[*i];
    p[*i] = p[*i+dir[*i]];p[*i+dir[*i]] = temp;
    //元素相关的箭头也得交换
    DIR T = dir[*i];dir[*i] = dir[*i+T];
    dir[*i+T] = T;
    *i = *i + T;    //使*i依旧是未交换前*i所指元素的下标
    return true;
}

函数功能:上述算法思路第三步,修改所以比k大的元素的箭头方向,原位修改
 输入参数:p ,指向n个字符的一个当前排列
         dir    ,标记p中每个元素的箭头方向
         k  ,p中处于活动状态的最大者的下标,由MaxActive函数求出
         N  in,缓冲区p的长度,也是待排列字符的个数
 返回值:   true 表示函数执行成功
        false 表示函数执行失败,失败原因为调用参数有误

bool ModifyDir(const char *p,DIR *dir,const int k,const int N)
{
    if(p == NULL || dir == NULL)return false;
    for(int i=0;i<N;i++)
        if(p[i]>p[k])
            dir[i] = (dir[i] == LEFT ? RIGHT : LEFT);
    return true;
}

int main()
{
    int N =0;cin>>N;
    char *p = new char [N+1];
    DIR *dir = new DIR [N];
    for(int i=0;i<N;i++)
    {
        p[i] = '1'+i;
        dir[i] = LEFT;
    }
    p[N]='\0';
    int k=0;
    cout<<p;
    int c = 1;
    do 
    {
        k = MaxActive(p,dir,N);
        if(k == N)
            break;
        Swap(p,dir,&k);
        ModifyDir(p,dir,k,N);
        cout<<"->"<<p;
        c++;
    } while (1);
    cout<<endl;
    cout<<c<<endl;
    delete []p;
    delete []dir;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值