今天,复习一下按字典序输出错排序列
思路探索:尝试将a放在1号位上,若a!=1且没有放在别的位置上,就将a放在1号位上并作标记;尝试将b放在2号位上,若b!=2且不位于其他位置上,将b放在2号位上,做标记,尝试将c放在3号位上,若c!=3且不位于其他位置上。下面来看一个例子,比如说我要得到1 2 3的错排序列,将2放在1号位,1放在2号位,3放在3号位,呃,出错了,不算,重来!说明21开头得不到错排序列。将2放在1号位,3放在2号位,1放在3号位,不行!1不能放在3号位,因为1被使用的标志是在第2位放1时被标记的,这说明啥?说明每次循环结束后就要取消有该循环带上的标记。
先敲一段字典序全排列输出错排序列的吧
//以字典序求全排列,并只输出错排序列
//思路:输出全排列,不是错排不输出
#include<stdio.h>
#include<string.h>
#define N 100
void swap(char *p,char *q)//如果不是全局变量,一定设计的参数是指针类型
{
char ch;
ch=*p;
*p=*q;
*q=ch;
}
//逆置以p,q为首尾地址的字符串
void reverse(char *p,char *q)
{//头指针,尾指针
while(p<q)
swap(p++,q--);//调用函数做的第一件事,实参求解,从右往左执行
//ch=*p;*p=*q;*q=ch;p++;q--;
}
void sort(char *s)
{
char *p,*q,ch;
int n=strlen(s);
for(p=s;p<=s+n-2;p++)//首地址传给字符指针 指向第一个 模拟n-1趟 s+n是\0的下标
for(q=p+1;q<=s+n-1;q++)//s+n-1 倒数第一个字符
//选择法排序
if(*p>*q)
swap(p,q);
}
int fun(char *s,char *t)
{//s指向的是准备判断的字符序列,t是准备错排的原始序列,只要有一个字符在正确位置上,就不是错排
while(*s)//*s!=0 *s!='\0'
{
if(*s==*t)//相等说明在正确位置上,不是错排
return 1;
s++;
t++;
}
return 0;
}
int permutation(char *s,char *t)
{
char *p,*q;
//对比字典序全排列,初值改变为0,因为字典序全排列已经输出最小串
int count=0;
while(1)
{
p=s+strlen(s)-1;
//从右往左找出第一对相邻的升序的元素
while(*(p-1)>*p)
{
p--;//不存在相邻的升序元素,即s为最大串
if(p==s)
return count;
}
q=p-1;//q为交换点
p=s+strlen(s)-1;//从右往左找到第一个大于*q的元素
while(*p<*q)
{
p--;
}
swap(p,q);
reverse(q+1,s+strlen(s)-1);
if(!fun(s,t))
{
puts(s);
count++;
}
}
}
int main()
{
char s[N],t[N];
int n;
gets(s);
if(s[0]==0)
return 0;
if(s[1]==0)
{
puts(s);
return 0;
}
strcpy(t,s);
sort(s);
printf("\n");
n=permutation(s,t);
printf("%d\n",n);
return 0;
}