大魔王程序员生成记#06.1#C语言习题

14 篇文章 0 订阅

目录

 

1.求斐波那契数列前40项

2.求连续子数组的最大和

3.辗转相处,求最大公约数

4.判断大小端

5.大小端的转换

6.int类型 指针  float  和零值如何比较

7.对指针的理解

8.const  和   define    区别??

9.求字符串单词个数

10.回文字符串

11.Here is Tulun ==>Tulun is Here

12.二分法查元素


1.求斐波那契数列前40项

解题思路:将前两项初始化为1,从第三项开始进行计算。

void Fabonacio(int *arr,int len)
{
	assert(arr != NULL && len > 0);
	arr[0] = 1;
	arr[1] = 1;
	for(int i = 2;i < len;i++)
	{
		arr[i] = arr[i-1]+arr[i-2];
	}
}
void Show(int *arr,int len)
{
	for(int i = 0;i < len;i++)
	{
		printf("%d ",arr[i]);
	}
	printf("\n");
}
int main()
{
	int arr[20] = {};
	int len = sizeof(arr)/sizeof(arr[0]);
	Fabonacio(arr,len);
	Show(arr,len);
	return 0;
}

递归版本:

int Job(int n)
{
	int f3=0;//第三项初始化
	if(n==2)
	{
		return 1;
	}
	if(n==1)
	{
		return 1;
	}
	else
	{
		f3=Job(n-1)+Job(n-2);//第三项==前两项的和
		return f3;
	}
}
int main()
{
	printf("%d\n",Job(8));
	return 0;
}

2.求连续子数组的最大和

void Job1(int arr[],int n)//传递数组和数组所包含元素个数
{
	int i,j,max,sum,start,end;
	max=arr[0];//将第一个元素付给max,相当于子序列只有一个元素时的最大值
	for(i=0;i<n;i++)
	{
		sum=arr[i];
		for(j=i+1;j<n;j++)
		{
			sum+=arr[j];//求连续子序列的和
			if(max<sum)//判断求和与max的大小
			{
				max=sum;
				start=i;//当数组的max发生改变时,记录开始上标==》有可能这个上下标之间的和是最大的
				end=j;//记录下标
			}
		}
	}
	printf("子数列的最大和为:%d\n",max);
	printf("开始下标为:%d\n",start);
	printf("结束下标为:%d\n",end);
}
int main()
{
	int arr[5]={10,-1,9,-100,-10};
	Job1(arr,5);
	return 0;
}

解题思路:累加与max进行比较,如果max发生改变,说明产生最大值(当前),记录当上时的起始和终止的下标。

int MaxNum(int *arr,int len)
{
	assert(arr != NULL && len > 0);
	int max = 0x80000000;
	int sum = 0;
	for(int i = 0; i < len;i++)
	{
		sum = 0;//第二趟的时候
		for(int j = i;j < len;j++)//O(n^2)
		{
			sum += arr[j];//10    9  18   -82 
			if(sum > max)
			{
				max = sum;//10  18
			}
		}
	}
	return max;
}
int MaxNum2(int *arr,int len)
{
	assert(arr != NULL && len > 0);
	int max = 0x80000000;
	int sum = 0;
	for(int i = 0; i < len;i++)
	{
		//sum = 0;
		if(sum <= 0)
		{
			sum = arr[i];//10
		}
		else 
		{
			sum += arr[i];//9  18  -82
		}

		if(sum > max)
		{
			max = sum;//10  18
		}
	}
	return max;
}
int main()
{
	int arr[10] = {};
	int len = sizeof(arr)/sizeof(arr[0]);
	int max = MaxNum2(arr,len);
	printf("%d\n",max);
	return 0;
}

3.辗转相处,求最大公约数

int Fun(int m,int n)//辗转相处,求最大公约数
{
	assert(m*n!=0);
	int tmp=0;
	if(m<n)
	{
		tmp=n;
		n=m;
		m=tmp;
	}
	while(m%n!=0)
	{
		tmp=m%n;//15  10===>5
		m=n;
		n=tmp;
	}
	return n;
}

4.判断大小端

bool IsBig()
{
	int a = 0x12345678;
	char *p = (char *)&a;
	if(*p == 0x78) 
	{
		return false;//小端
	}
	else
	{
		return true;//大端
	}
}

联合体判断大小端

union Data
{
	int a;
	char b;
};
void Job(Data test)
{
	if(test.b==0x78)
	{
		printf("小端储存\n");
	}
	else
	{
		printf("大端储存\n");
	}
}

解题思路:联合体共用一块内存,同一时间只保存一个数据

5.大小端的转换

void Job(char *p,int len)
{
	  int n=len/2;        //将数据一分为二 1234 5678
	  char c;
	  for(int i=0;i<n;i++)//相互调换
	  {
		  c=*(p+i);
		  *(p+i)=*(p+(len-i-1));
		  *(p+(len-i-1))=c;
	  }  
}
int main()
{

	char arr[]="Here  is  Tulun";
	printf("%s\n",arr);
	int len=sizeof(arr)/sizeof(arr[0]);
	Job1(arr,len);
	printf("%s\n",arr);
	return 0;
}

 解题思路:将数据一分为二1234 5678

另一个版本:

unsigned int  Fun(unsigned int n)
{
	return ( ((n&0xff000000) >>24) | ((n&0x00ff0000) >>8)
	| ((n&0x0000ff00) <<8) | ((n&0x000000ff) <<24) );
}
int main()
{
   unsigned int n=0x12345678;
   Fun(n);
   return 0;
}

6.int类型 指针  float  和零值如何比较

解:
(1)int类型:
int i=0;
if(i==0);if(i!=0);
直接和0比较就好。
(2)指针:
int *p=NULL;
if(NULL==p);if(NULL!=p);
为什么要这样写,因为1.怕漏写一个'=';2.NULL表示的是内存中的起始地址,即0x00000000。NULL在数值上==0;
(3)float类型:
float a=0.0;
if((a>=-EPSINON)&&(a<=EPSINON));
因为float和double是有精度限制的,不能够直接拿来和0.0进行比较。必须设置一个精度范围,而假设EPSINON是一个定义好的精度,如果一个数能够落在[0.0-EPSINON,0.0+EPSINON]这个区间之内,则说明在某个精度内与零值相等。
(4)bool类型:
bool flag=false;
if(flag);if(!flag);
bool类型本身返回的就是true或false,1或者0。所以在与“零值”判断时直接使用变量本身。
但有的编译器对true定义的不是1,所以要初始化一个0,判断0和非0即可。
一般情况下对bool类型的初始化都为false,这是因为如果不进行初始化,默认的地址是随机分配的,即非0值,所以要对bool进行初始化,并赋值为false。

7.对指针的理解

在定义指针时我们常写成int a=5;int *p;p=&a;这个东西就弄的我很茫然,有时候书上又会出现一句“int *p=5;”我根本分不清他们两者之间的区别。而在xxx的书上说的他们是一样的。但其实他们真的是不一样,定义int *p;这样写应该是为了好看,它实际应该写成int* p;这样的定义才能让人理解这是定义了一个指向int型的指针,它叫做p,这个p只能放地址,如果你写成了"int *p=5;"这个5就会被当做是地址处理。定义指针时要初始化给NULL,这是因为在编译其中NULL就表示的是内存的其实地址,也就是0x00000000.它的作用就是初始化指针变量,不让指针变量指向一个非法的地址。

8.const  和   define    区别??

解:
const修饰的是"只读的变量",其值在编译时不能被使用。所以可以理解为const==readonly。
const修饰的只读变量是在编译的时候确定其值,而define宏定义是在预编译的时候进行替换。
const修饰的只读变量有类型,而define宏定义没有,只是常数。
编译器会给const修饰的只读变量做类型校验,减少错误的可能,而define宏定义没有。
编译器不为const修饰的只读变量分配存储空间,而将它们保存在符号表中,只读变量在运行中只有一份备份;
而define宏定义在内存中有若干个备份。

const修饰的只读变量必须在定义的同时初始化,因为const修饰的是只读变量只能读,不能写。在定义之后就不能再进行修改,所以要定义的同时初始化。

9.求字符串单词个数

int Job(char *str)
{
	int sum=0;//用来记录两个词之间的空格数
	char *pbegin=str;
	char *pend=str;
	assert(str!=NULL);
	while(*pend!='\0')
	{
		if(*pbegin==' ')//如果起始输入的是空格,则将指针移向第一个字母
		{
			while(*pbegin==' ')
			{
				pbegin++;
				pend++;
			}
		}
		if(*pend==' '&&*(pend+1)!=' '&&*(pend+1)!='\0')//记录两个词中间的空格,且只记录一次,考虑最后的'\0'。
		{
			sum++;
		}
		pend++;
	}
	return sum+1;
}
int main()
{
	char str[]="   ghgh  asdjk  sjdks ss jkj   ";
	printf("单词个数为:%d\n",Job(str));
	return 0;
}

解题思路:在字符串中,判断他们有多少个空格(两个词中必有空格),记录空格数。

10.回文字符串

//"abcba"===》回文字符串
//思路:*pbegin *pend如果他俩值得数一直相等,则他就是一个回文数
void Fun(const char *str)
{
	const char *pbegin=str;
	const char *pend=str;
	assert(str!=NULL);
	while(*pend!='\0')
	{
		pend++;
	}
	pend--;
	while(pbegin<pend)//地址
	{
		if(*pbegin==*pend)
		{
			pbegin++;
		    pend--;
		}
		else
	{
		printf("%s不是一个回文数\n",str);
		break;
	}	
	}
	printf("%s是一个回文数\n",str);	
}
int main()
{
	char str[]="123421";
	Fun(str);
	return 0;
}

解题思路:*pbegin *pend如果他俩值得数一直相等,则他就是一个回文数。

11.Here is Tulun ==>Tulun is Here

/*
一级指针存放的是变量的地址,二级指针存放的是一级指针的地址
*/
void Reverse(char *pbegin,char *pend)
{
	assert(pbegin!=NULL&&pend!=NULL);
	char tmp=0;
	while(pbegin<pend)//地址
	{
		tmp=*pbegin;
		*pbegin=*pend;
		*pend=tmp;
		pbegin++;
		pend--;
	}
}

char* RevreSentence(char *str)// 
{
	assert(str!=NULL);
	char *pbegin=str;
	char *pend=str;
	while(*pend!='\0')
	{
		pend++;
	}
	pend--;
	Reverse(pbegin,pend);
	pbegin=str;
	pend=str;
	while(*pbegin!='\0')
	{
		if(*pbegin==' ')
		{
			pbegin++;
			pend++;
		}
		else
			if(*pend==' '||*pend=='\0')
			{
				Reverse(pbegin,--pend);
				pbegin=++pend;
			}
			else
			{
				pend++;
			}
	}
	return str;
}
int main()
{
	char str[]="Here is Tulun";//不能写成*str="Here is Tulun";因为字符串不能修改
	RevreSentence(str);
	printf("%s\n",str);
	return 0;
}

解题思路:整体逆置,再对每一个单词进行逆置。

12.二分法查元素

int Binarrserach(int *arr,int len,int key)
{
	int low=0;
	int high=len-1;
	while(low<=high)
	{
		int mid=(low+high)/2;//int mid=(low+high)>>1;
		if(arr[mid]==key)
		{
			return mid;
		}
		else
		{
			if(arr[mid]>key)
			{
				high=mid-1;
			}
			else
			{
				low=mid+1;
			}
		}
	}
	return -1;
}
int main()
{
	int arr[]={1,2,3,4,5,6,7};
	int len=sizeof(arr)/sizeof(arr[0]);
	printf("%d\n",Binarrserach(arr,len,4));
	printf("%d\n",Binarrserach(arr,len,10));
	return 0;
}

递归版本:

int Job1(int *arr,int low,int high,int key)//设置指向第一个元素的下标low和最后一个元素的下标high
{
	int mid=(low+high)/2;
	if(arr[mid]==key)
	{
		printf("%d的下标为:%d\n",key,mid);
		return mid;
	}
	else
	{
		if(arr[mid]>key)
		{
			Job1(arr,low,mid-1,key);//改变范围
		}
		else
		{
			Job1(arr,mid+1,high,key);
		}
	}
}
int main()
{
	int arr[5]={1,2,3,4,5};
	Job1(arr,0,4,4);
	return 0;
}

注:所有的递归都发生在栈上   要控制递归的次数,不然会挤爆

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值