扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
正如
创新互联专注于托克托网站建设服务及定制,我们拥有丰富的企业做网站经验。 热诚为您提供托克托营销型网站建设,托克托网站制作、托克托网页设计、托克托网站官网定制、小程序设计服务,打造托克托网络公司原创品牌,更为您提供托克托网站排名全网营销落地服务。
楼下
所言
int
**p
,定义的p是一个指向int*型的
指针
int
(*p)[10]是一个指向
数组
的指针
数组长度为10
假如定义成
deal(int
**p),传
参数
时要加强制类型转换:
deal((int**)a);
并且使用p时不能用
下标
,p[2][3]是错误的,因为不知道p指向的int*型的长度,无法编译成*(p+2*10+3)
必须自己写成*(p+2*10+3)来调用
假如定义成
deal(int
(*p)[10])就不一样了,
编译器
就能知道p是一个指向长度为10的数组的指针
那么p[2][3]就能编译成*(p+2*10+3)了
总之,C语言是很灵活的,不同的定义
方式
配上不同的
用法
,都是能得到正确的结果的
不知道这么说楼主明白了没?
同样的还有
多维数组
对多维指针的问题,楼主可以自己类推一下
#includestdio.h
int deal(int a[],int m,int up[]);
int main()
{
int i,j,count=0;
int score[]={1,2,3,4,5,6,7,8,9,0,10},up[100]={-1};
count=deal(score,11,up);
printf("%d\n",count);
for(i=0;icount;i++)
printf("%-4d",up[i]);
return 0;
}
int deal(int a[],int m,int up[])
{
double sum=0,aver;
int i=0,count=0,j=0;
while(im)
{
sum=sum+a[i];
i++;
}
aver=sum*1.0/m;
for(i=0;im;i++)
{
if(a[i]aver)
{
count++;
up[j]=a[i];
j++;
}
}
return count;
}
输出为:
5
6 7 8 9 10
但是数字要是大且多得话,就得考虑溢出了!
给你第一个问题的答案,第二个你需要自己学着练习。
#includetime.h
int main(){
int cards[52];
int everycards[4][13];
int i = 0;
//init
for(i=0;i52;i++){
cards[i] = i + 1;
}
shuffle(cards,52);
sort(cards,0,13);
sort(cards,13,13);
sort(cards,26,13);
sort(cards,39,13);
deal(everycards,cards);
display(everycards);
return 0;
}
void deal(int(*everycards)[18], int *cards){
int i,j;
for(i=0;i4;i++){
for(j=0;j13;j++){
everycards[i][j] = cards[i*13+j];
}
}
}
void display(int (*everycards)[18]){
int i,j;
putchar('\n');
printf("开始发牌:\n");
for(i=0;i4;i++){
printf("%d号手上的牌是:",i);
for(j=0;j13;j++){
if(everycards[i][j]=1 everycards[i][j]=10){
printf("方块%d ",everycards[i][j]);
}else if(everycards[i][j]=14 everycards[i][j]=23){
printf("梅花%d ",everycards[i][j]-13);
}else if(everycards[i][j]=27 everycards[i][j]=36){
printf("红桃%d ",everycards[i][j]-26);
} else if(everycards[i][j]=40 everycards[i][j]=49){
printf("黑桃%d ",everycards[i][j]-39);
}else{
switch(everycards[i][j]){
case 11:printf("方块J ");break;
case 12:printf("方块Q ");break;
case 13:printf("方块K ");break;
case 24:printf("梅花J ");break;
case 25:printf("梅花Q ");break;
case 26:printf("梅花K ");break;
case 37:printf("红桃J ");break;
case 38:printf("红桃Q ");break;
case 39:printf("红桃K ");break;
case 50:printf("黑桃J ");break;
case 51:printf("黑桃Q ");break;
case 52:printf("黑桃K ");break;
}
}
}
putchar('\n');
putchar('\n');
}
}
void shuffle(int *cards, int lenth)
{
int temp, i, index;
time_t t;
srand((unsigned int)(t));
for (i = 0; i lenth - 1; i++) //保证每一次交换都是和剩下的数进行交换
{
index = rand() % (lenth - i) + i;
if (index != i)
{
temp = cards[i];
cards[i] = cards[index];
cards[index] = temp;
}
}
}
//
void sort(int *a,int start, int l){
int i,j;
int m,n;
int v;
for(i=start;istart+l-1;i++){
for(j=i+1;jstart+l;j++){
m = a[i]%l;
n = a[j]%l;
if(m==0){
m = 13;
}
if(n==0){
n = 13;
}
if(mn){
v = a[i];
a[i] = a[j];
a[j] = v;
}
}
}
}
1.楼主的数太多了,我的机器有点落伍,显示的时间有点漫长~~~~,我把数改成了1,2,3,3,4,7,7。显示上也简单点,原理是一样的。。。另外不是很清楚楼主的所有组合是不是包括取出一部分字符串做排列组合,我弄的是所有
数字用上的全排列,就是没有12,13这样的组合数,楼主如果是需要显示这样的数,只要在主函数中做循环,分别取出1至7个数再运行deal和排列函数就行(注,调试环境是VC++6.0)
#include "stdio.h"
#include "stdlib.h"
#define NUM 30
#define N 7 //数组元素个数
static int cnt=0;//用于记录重复数字的个数
void print(int n,int arr[]){
int i;
static int count=0;
printf("%d:",++count);
for(i=0;in;i++)
printf("%d",arr[i]);
printf("\t");
if(count%5==0)
printf("\n");
}
void arrange(int size,int arr[],int p){
//算法思想:采用经典回溯法,先确定第一个位置,再对余下的n-1位数字做全排列
//每组全排列后均把所有参与此次全排列的数与这次全排列的第一个数交换后再重复排列
//例如递归到排列1234后回溯一次即排列34,将4与3交换,再回溯至排列234分别将34与2交换后排列
//直至排列完成后,再分别将234与1交换后排列
//不过算法效率在数字过大后就比较低下了,楼主可以去网上找找更高效的算法
int i,temp;
if(p+1==size){//排列完成后打印
print(size,arr);
return;
}
for(i=p;isize;i++){//交换
temp=arr[p];
arr[p]=arr[i];
arr[i]=temp;
arrange(size,arr,p+1);//递归调用排列
temp=arr[p];
arr[p]=arr[i];
arr[i]=temp;
}
}
void deal(int a[],int b[]){
//将重复数字去掉,方便全排列
int i,j;
for(i=0;iN;i++){
if(a[i]0){
for(j=i+1;jN;j++){
if(a[i]==a[j]){
a[j]=-1;//重复标志
cnt++;
}
}
}
}
j=0;
for(i=0;i=N;i++){
if(a[i]0){
b[j++]=a[i];
}
}
}
void main(){
int a[N]={1,2,3,3,4,7,7};
int b[NUM];
deal(a,b);//处理数组
arrange(N-cnt,b,0);//排列输出
}
2.和第一问一样,我只选了1,2,3,3,4,7,7。程序上只是打印函数改了下,deal函数做了调整,本来想在第一问的排列基础上再在特定的位置上插入3和7,后来发现会重复,做了很久的无用功啊。。print中的循环太多了,看起来有点累,不过主要的就是两个大的东西,两个循环实际是一样的原理,楼主有兴趣可试着把循环换成一个函数,可读性会强点。下面的代码适用性还是很广的。
#include "stdio.h"
#include "stdlib.h"
#define NUM 30
#define N 7
static int cnt=0;//用于记录重复数字的个数
static int t[N];//用于记录重复数字
void print(int n,int arr[]){
//算法思想:对有重复的数字组合排列,将它看成是对空余位置填充数字
//先将重复的数字进行填充,即在空余位置中取定重复数的位置,再对余下的位置进x行全排列填充
//按此思想得到的个数为 =1260个
int a1[N-2],a2[N];
static int count=0;
for(int i=0;iN-cnt/2-1;i++){
//取5个数,包括完全没重复的数再加上重复的数(例如:1,2,4,3,3)
//对这5个数按照算法思想排列
a1[i]=t[0];
for(int j=i+1;j=N-cnt/2-1;j++){
a1[j]=t[0];
for(int k=0;ki;k++)
a1[k]=arr[k];
for(int m=i+1;mj;m++)
a1[m]=arr[m-1];
for(int p=j+1;pN-cnt/2;p++)
a1[p]=arr[p-2];
for(int s=0;sN-1;s++){//将7个数取出按照算法排列
a2[s]=t[1];
for(int r=s+1;r=N-1;r++){
a2[r]=t[1];
for(int y=0;ys;y++)
a2[y]=a1[y];
for(int x=s+1;xr;x++)
a2[x]=a1[x-1];
for(int h=r+1;hN;h++)
a2[h]=a1[h-2];
printf("%d:",++count);
for(int c=0;cN;c++)//将该排列打印出来
printf("%d",a2[c]);
printf("\t");
if(count%5==0)
printf("\n");
}
}
}
}
}
void arrange(int size,int arr[],int p){
int i,temp;
if(p+1==size){//排列完成后打印
print(size,arr);
return;
}
for(i=p;isize;i++){//交换
temp=arr[p];
arr[p]=arr[i];
arr[i]=temp;
arrange(size,arr,p+1);//递归调用排列
temp=arr[p];
arr[p]=arr[i];
arr[i]=temp;
}
}
void deal(int a[],int b[]){
//将数组处理成只剩不重复排列的数
int i,j,k=0;
for(i=0;iN;i++){
if(a[i]0){
for(j=i+1;jN;j++){
if(a[i]==a[j]){
t[k++]=a[i];//记录重复数
a[i]=-1;
a[j]=-1;
cnt+=2;
}
}
}
}
j=0;
for(i=0;i=N;i++){
if(a[i]0){
b[j++]=a[i];
}
}
}
void main(){
int a[N]={1,2,3,3,4,7,7};
int b[NUM];
deal(a,b);//处理数组
arrange(N-cnt,b,0);//排列输出
}
3.第三问比较简单,在第二问打印程序上加上限制条件(即第三位不能是3,第七位不能是七)
#include "stdio.h"
#include "stdlib.h"
#define NUM 30
#define N 7
static int cnt=0;//用于记录重复数字的个数
static int t[N];//用于记录重复数字
void print(int n,int arr[]){
int a1[N-2],a2[N];
static int count=0;
for(int i=0;iN-cnt/2-1;i++){
a1[i]=t[0];
for(int j=i+1;j=N-cnt/2-1;j++){
a1[j]=t[0];
for(int k=0;ki;k++)
a1[k]=arr[k];
for(int m=i+1;mj;m++)
a1[m]=arr[m-1];
for(int p=j+1;pN-cnt/2;p++)
a1[p]=arr[p-2];
for(int s=0;sN-1;s++){
a2[s]=t[1];
for(int r=s+1;r=N-1;r++){
a2[r]=t[1];
for(int y=0;ys;y++)
a2[y]=a1[y];
for(int x=s+1;xr;x++)
a2[x]=a1[x-1];
for(int h=r+1;hN;h++)
a2[h]=a1[h-2];
if(a2[2]!=t[0]a2[6]!=t[1]){
printf("%d:",++count);
for(int c=0;cN;c++)
printf("%d",a2[c]);
printf("\t");
if(count%5==0)
printf("\n");
}
}
}
}
}
}
void arrange(int size,int arr[],int p){
int i,temp;
if(p+1==size){//排列完成后打印
print(size,arr);
return;
}
for(i=p;isize;i++){//交换
temp=arr[p];
arr[p]=arr[i];
arr[i]=temp;
arrange(size,arr,p+1);//递归调用排列
temp=arr[p];
arr[p]=arr[i];
arr[i]=temp;
}
}
void deal(int a[],int b[]){
//将数组处理成只剩不重复排列的数
int i,j,k=0;
for(i=0;iN;i++){
if(a[i]0){
for(j=i+1;jN;j++){
if(a[i]==a[j]){
t[k++]=a[i];//记录重复数
a[i]=-1;
a[j]=-1;
cnt+=2;
}
}
}
}
j=0;
for(i=0;i=N;i++){
if(a[i]0){
b[j++]=a[i];
}
}
}
void main(){
int a[N]={1,2,3,3,4,7,7};
int b[NUM];
deal(a,b);//处理数组
arrange(N-cnt,b,0);//排列输出
}
没看清题目,原来你还要求——每一次的交换必须是上一组两个同学之间的交换,其实用递归函数递归还是可以的呀!只需要增加一个数组n[4](如果是N个同学之间的交换就设n[N-1]).
deal(l)函数——它只负责找出l号位置该站哪位同学,这名同学只能从上次0~(l-1)位置上已经站好的同学中选择出,并与l位置的同学作交换,(deal(l)函数会把“具体”找l号以下位置应该站哪些同学的任务交由deal(l-1)来处理),直到deal(0)负责0位置该站谁(此时已经结束,0号位置以下已经没同学可与0位置同学作交换了)。
这种思想仍然是递归,也就是回答者: suzhijie325 所说的思想!
问题的关键是:
对于deal(l)函数,我们必须要保证每一次被交换到l号位置的同学都是不同的,用什么来保证呢?设置一个数组n[4]!
它的作用是:
记录l号位置的同学变动情况(l号位置的同学只能与l号位置以下的同学交换),然后利用以下语句,在0~(l-1)位置中寻找出在n[4]中没有的同学(这名同学的位置是k),然后把此同学交换到l号位置。另外也不要忘记把l号位置的同学记录到n[]数组中!!
============================================================================
for(k=0;kl;k++)
{ flagy=1;
for(n_i=0;n_i=n_p;n_i++)
{
if(b[ml][k]==n[n_i])
{flagy=0;break;}
}
if(flagy)
{break;}
}
n[++n_p]=b[ml][l];
b[m][l]=b[ml][k],b[m][k]=b[ml][l];/*第k号位置处的同学与第l号位置的同学交换位置*/
==================================================================================
整个程序在如下:
#includestdio.h
#define N 5
int b[120][N]={1,2,3,4,5};
int m=0;
int deal(int l)
{int i,j;
int ml;
int n[4]={0};
int n_p=-1,n_i,n_j;
int k=0;
int flagy;
if(l==0)
return ++m;
deal(l-1);
for(i=0;il;i++)
{ ml=m-1;
for(j=0;j5;j++)
{
b[m][j]=b[ml][j];
}
for(k=0;kl;k++)
{ flagy=1;
for(n_i=0;n_i=n_p;n_i++)
{
if(b[ml][k]==n[n_i])
{flagy=0;break;}
}
if(flagy)
{break;}
}
n[++n_p]=b[ml][l];
b[m][l]=b[ml][k],b[m][k]=b[ml][l];/*第k号位置处的同学与第l号位置的同学交
换位置*/
deal(l-1);
}
}
void main()
{
int l=N-1;int i,j;unsigned char pause=0x80;
deal(l);
for(i=0;i120;i++)
{if((pause=pause1)==0)
{getchar();pause=0x80;}
for(j=4;j=0;j--)
printf("%d ",b[i][j]);
printf("\n");
}
printf("It has %d categorys in total!\n",m);
}
=====================================================================================
上次的程序(只找出120种组合情况)
#includestdio.h
int b[120][5]={1,2,3,4,5};
int m=0;
int deal(int l)
{int i,j;
int ml=m;
if(l==0)
return ++m;
deal(l-1);
for(i=0;il;i++)
{
for(j=0;j5;j++)
{
b[m][j]=b[ml][j];
}
b[m][l]=b[ml][i],b[m][i]=b[ml][l];/*第i号同学与l号同学交换位置*/
deal(l-1);
}
}
void main()
{
int l=4;int i,j;char c=0x10;
deal(l);
for(i=0;i120;i++)
{if((c=c1)==1)/*由于数据组合种类很多,这条if语句实现的是显示暂停(getchar())*/
{getchar();c=0x10;}
for(j=4;j=0;j--)/*输出组合*/
printf("%d ",b[i][j]);
printf("\n");
}
printf("the m is %d\n",m);
}
首先的首先……少包含一个头文件"stdlib.h"
malloc的定义在这个头文件里~~
正题:分析程序,通常两方面入手,变量含义,函数功能。
首先,变量含义:
int **a,length,k=0,l=0,i,j,number=0,turn[4]={-1,0,1,0};
分别为:
**a:一个指向二维数组的指针,用来保存需要填充的所有整数。
length:输入的正整数
k:下一个整数应当填入位置的行下标
l:下一个整数应当填入位置的列下标
i和j:循环变量
number:当前填充的填充方向,0=向上,1=向右,2=向下,3=向左
turn:借助number来调整k和l的取值,即:
当向上填充时,l不变,k减1
当向右填充时:l加1,k不变
当向下填充时,l不变,k加1
当向左填充时,l减1,k不变
scan函数功能显而易见,读出length并初始化数组a为0
deal函数是算法的关键,而判断语句则是核心:
把每个条件式分开来看,
if(
//首先你要明确turn[number]表示按当前填充方向,行下标的变化情况,即+1,-1或不变。同理turn[(number+1)%4]表示按当前填充方向列下标的变化情况。
k+turn[number]==length
//这句就好懂了,如果按当前填充方向填充后,行下标是否已经超过最下端了,换言之,判断当前是否已经填到最后一行了,且当前的填充方向仍是向下的。
||
k+turn[number]==-1
//与上句相反,这句判断当前是否填到第一行了且方向向上。
||
l+turn[(number+1)%4]==length
//功能同前,判断当前是否填到了最右端一列且方向向右。
||
l+turn[(number+1)%4]==-1
//判断当前是否填到了最左端一列且方向向左。
||
a[k+turn[number]][l+turn[(number+1)%4]]!=0
//这句是判断如按当前填充方向将要填充的位置上是否已经被填充上了。
)
number=(number+1)%4;
//如果满足了上述任意条件,就顺时针更改填充方向,
l+=turn[(number+1)%4];
k+=turn[number];
//以上两句确定本轮整数应填入的行列下标。
好了,整个程序就是这么个思路,理顺一下,还是比较有趣的~~
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流