C的几个小程序和概念(常见操作)(下)
1、排列问题
输出n中取m无重复的元素排列情况。
用递归实现
#include "iostream"
using namespace std;
char f[27];//最多用个字母来表示排列情况
char p[27];//来标识当前字母的获取情况。都从开始,不用。自动初始化为
int m,n;//从n个数中取m个数
FILE *fp=fopen("c:\\pailie.txt","w+");
void pa(int k){
if(k>m) //已取够了m个了,则输出
{
for(int i=1;i<=m;i++)
//putchar(p[i]+'A'-1);
fprintf(fp,"%c",p[i]+'A'-1);
//cout<<endl;//输出,换行,返回
fprintf(fp,"%c",'\n');
return;
}//if
//还没有取够m个
for(int i=1;i<=n;i++)
if(!f[i])
{
f[i]=1;//将当前的这个字母作标记
p[k]=i;//将当前的这个字母取上
pa(k+1);//继续取下一个字母
f[i]=0;//将取出的第i个元素重新放入集合S,关键
}//if
}//pa
int main(){
cout<<"Input n m of P(n,m)=";
cin>>n>>m;
//...进行n,m合乎规定逻辑的判断
if(!fp) {
cout<<"error";
return 1;
}
pa(1);//先找第一个字符
}
2、组合问题
取n个数字中可重复的m个数的情况
#include "iostream"
using namespace std;
char f[27];//最多用个字母来表示排列情况
char p[27];//来标识当前字母的获取情况。都从开始,不用。自动初始化为
int m,n;//从n个数中取m个数
//FILE *fp=fopen("c:\\pailie.txt","w+");
void pa(int k,int share){
if(k>m) //已取够了m个了,则输出
{
for(int i=1;i<=m;i++)
putchar(p[i]+'A'-1);
//fprintf(fp,"%c",p[i]+'A'-1);
cout<<endl;//输出,换行,返回
//fprintf(fp,"%c",'\n');
return;
}//if
//还没有取够m个
for(int i=share+1;i<=n;i++)
if(!f[i])
{
f[i]=1;//将当前的这个字母作标记
p[k]=i;//将当前的这个字母取上
pa(k+1,i);//继续取下一个字母
f[i]=0;//将取出的第i个元素重新放入集合S,关键
}//if
}//pa
int main(){
cout<<"Input n m of P(n,m)=";
cin>>n>>m;
//...进行n,m合乎规定逻辑的判断
//if(!fp) {
// cout<<"error";
// return 1;
// }
pa(1,0);//先找第一个字符
}
我们分析问题,可以知道,组合问题是:为了避免重复,取下一个元素时,必须在当前元素的下一位置开始探索。所以再传递一个share变量,以便下一次搜索时从下一个位置开始就好了。
3、八皇后问题
每列必然有一个皇后,每行必然有一个皇后。
放下一列放置皇后时,我们要找的是应当放置在该列的那一行,这样我们与前面的所有列放置的皇后进行操作探索,看是否满足条件。
不满足条件的定义是:(因为是在不同列试探,所以列肯定不同)同处于同一行,或在45角方向上。用(k,j)来描述,k表示列号,j表示行号。
试探过程中,如果第k个皇后无位置可放,则退回上一列,试探第k-1皇后的下一个可放位置,依次类推。这样一直回溯到第一个皇后,如果第一个皇后试完最后一个行号8,则算法停止。
#include "cmath"
#include "iostream"
using namespace std;
int row[8];//由于我们是每一列逐一进行试探,所以只需要保存每一列的行号就可以了。
int count;
void arrange(int k){//试探第k列
int i,j;
if(k>8){//第k列也放置好了,说明存在一个可放置的行系列,输入之
for(i=1;i<=8;i++)
cout<<row[i]<<" "; //输出每一列的行号
cout<<endl;
count++;
return;
}//if
for(j=1;j<=8;j++){//试探当前列的每一行是否满足条件
for(i=1;i<k;i++)//将当前列的第一行都与前面k-1列放置的皇后位置进行判断,看当前列的试探行是否满足条件
if(row[i]==j||(k-i)==abs(j-row[i]))//与前面的任何一个皇后同行,或位于角上,则退出此处试探,进行下一轮
break;
if(i>=k)//当前第k列的第j行满足条件,记录
{
row[k]=j;
arrange(k+1);//继续放置下一列的皇后
}//if
}//for
}//arrange
int main()
{
arrange(1);
cout<<count<<endl;
}
可以得出,是92种。
4、关于new和delete的几个操作
int(*p)[3][4]=new int[2][3][4];//int(*p)[3][4]=(int(*)[3][4])malloc(2*sizeof(int[3][4]));
char **s=new char*[10];//char **s=(char**)malloc(10*sizeof(char*))
int(**p)()=new(int(*)[7]());//int(**p)()=(int(**)())malloc(sizeof(int(*[7])()));
5、字符I/O
输入
int fgetc( FILE *stream );
int getc( FILE *stream );
int getchar( void );//get the char from the stdin
返回int主要是为了允许函数报告文件的末尾EOF
输出
int fputc( int c, FILE *stream );
int putc( int c, FILE *stream );
int putchar( int c );
fgetc,fputc是函数,其它几个都是宏。
撤销字符
int ungetc( int c, FILE *stream );
如果多个字符返回一个流中,则再次读时以反序进行。退回到流和写入到流中不相同。如果用fseek,rewind改变了流的位置,则退回的字符会丢弃。
#include <stdio.h>
#include <ctype.h>
void main( void )
{
int ch;
int result = 0;
printf( "Enter an integer: " );
/* Read in and convert number: */
while( ((ch = getchar()) != EOF) && isdigit( ch ) )
result = result * 10 + ch - '0'; /* Use digit. */
if( ch != EOF )
ungetc( ch, stdin ); /* Put nondigit back. */
printf( "Number = %d\nNextcharacter in stream = %c%c",
result, getchar(), getchar());
}