01 求第二大数
题目描述:
写一个函数找出一个整数数组中,第二大的数
代码:
#include <stdio.h>
#define N 105
int secondMax(int a[],int n){
int Max=a[0],s_Max=-32767;
int i;
for(i=1;i<n;i++){
if(a[i]>Max){
s_Max=Max;
Max=a[i];
}
else if(a[i]<Max){ //大小相同则不作任何操作
if(a[i]>s_Max)
s_Max=a[i];
}
}
return s_Max;
}
int main(){
int a[N];
int n,i,ans;
while(scanf("%d",&n)!=EOF){
for(i=0;i<n;i++){
scanf("%d",&a[i]);
}
ans=secondMax(a,n);
printf("%d\n",ans);
}
return 0;
}
02 计算N的阶乘
题目描述:
编程计算n!的值
代码 1 (n!在int范围内)
#include <stdio.h>
int multi(int ans, int n){
int i;
for(i=n;i>0;i--){
ans=ans*i;
}
return ans;
}
int main(){
int n,ans;
while(scanf("%d",&n)!=EOF){
ans=1;
ans=multi(ans,n);
printf("%d\n",ans);
}
return 0;
}
代码 2 (n!不在int范围内,n在int范围内)
#include <stdio.h>
#include <stdlib.h>
#define N 10
//大整数乘法
struct bign{
int data[1000];
int len;
};
bign multi(bign x,int y){
int carry=0,i; //carry表示进位
for(i=0;i<x.len;i++){
int temp=x.data[i]*y+carry;
carry=temp/N;
x.data[i]=temp % N;
}
while(carry){
x.data[i++]=carry % N;
carry=carry/N;
}
x.len=i; //更新长度
return x;
}
int main(){
int i,n;
struct bign a;
while(scanf("%d",&n)!=EOF){
a.data[0]=1;
a.len=1;
for(i=2;i<=n;i++){
a=multi(a,i);
}
//输出结果
for(i=a.len-1;i>=0;i--){
printf("%d",a.data[i]);
}
printf("\n");
}
return 0;
}
03 字符 i 首次出现的位置
题目描述:
设有一个字符串“This is a computer”,请编程求字符“i”首次出现的位置。(字符i 与字母i )
代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define N 1001
int main(){
char str[N]={0},c1,c2;
int pos=-1,i;
while(gets(str)!=NULL){
printf("所输入的是:%s\n",str);
//scanf("%c",&c1);
c1=getchar();
printf("要查找的是:%c\n",c1);
getchar(); //需要吸收换行符
if(c1>='A' && c1<='Z') //issuper(cl),是-1,不是-0
c2=c1+32; //c2=tolower(c1),转换为小写
if(c1>='a' && c1<='z') //islower(cl),是-1,不是-0
c2=c1-32; //c2=toupper(c1),转换为大写
int len=strlen(str);
printf("len=%d\n",len);
for(i=0;i<len;i++){
if(str[i]== c1 || str[i]==c2){
pos=i+1;
break;
}
}
printf("pos=%d\n",pos);
}
return 0;
}
04 Fibonacci数列
题目描述:
生成Fibonacci数列的前20项并输出
代码:
#include <stdio.h>
#define N 101
int main(){
int n,i;
int a[N];
a[1]=1,a[2]=1;
while(scanf("%d",&n)!=EOF){
if(n<2 && n>0)
for(i=1;i<=n;i++)
printf("%d ",a[i]);
else{
printf("%d %d ",a[1],a[2]);
for(i=3;i<=n;i++){
a[i]=a[i-1]+a[i-2];
printf("%d ",a[i]);
}
}
printf("\n");
}
return 0;
}
05 名称排序
题目描述:
输入五个国家的名称,按字母顺序排列输出
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char country[5][20];
char temp[20];
int i,j;
for(i=0;i<5;i++){
scanf("%s",country[i]);
}
for(i=0;i<5;i++){
for(j=i+1;j<5;j++){
if(strcmp(country[i],country[j])>0){
strcpy(temp,country[j]);
strcpy(country[j],country[i]);
strcpy(country[i],temp);
}
}
puts(country[i]);
}
return 0;
}
指针实现字符串排序
指针实现对字符串排序,输出排序后的字符串。
#include <stdio.h>
#include <string.h>
#define MAX 20
int main(){
void sort(char **p);
int i;
char **p,*pstr[5],str[5][MAX];
for(i=0;i<5;i++){
pstr[i]=str[i]; //将第i个字符串的首地址赋予指针数组pstr的第i个元素
}
printf("input 5 strings:\n");
for(i=0;i<5;i++){
scanf("%s",pstr[i]);
}
p=pstr;
sort(p);
printf("\nstrings sorted:\n");
for(i=0;i<5;i++){
printf("%s\n",pstr[i]);
}
return 0;
}
void sort(char **p){
int i,j;
char *temp;
for(i=0;i<5;i++){
for(j=i+1;j<5;j++){
if(strcmp(*(p+i),*(p+j))>0) //比较后交换地址
{
temp=*(p+i);
*(p+i)=*(p+j);
*(p+j)=temp;
}
}
}
}
06 字符串替换
题目描述:
将字符串S1中出现的所有S2都替换成S3, 并且不损坏字符串S1。函数原型为:char exchange(char S1, char S2, char S3)
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *exchange(char *str1, char *str2, char *str3){
char*p,*q,*r,*s;
int len1,len2,len3,i=0,len; //len表示新串的长度
len1=strlen(str1);
len2=strlen(str2);
len3=strlen(str3);
p=str1;
//统计一个字符串在另一个字符串中出现次数
while((p=strstr(p,str2))!=NULL){
i++; //统计str2出现的次数
p+=len2;
}
len=len1-i*len2+i*len3;
s=r=(char *)malloc(len);//分配动态存储空间
p=str1;
while(1){
q=strstr(p,str2); //str2串是否在s1中出现,返回首次出现位置
if(q!=NULL){
i=q-p; //出现位置距离开始位置距离
strncpy(r,p,i); //先写串str1的前i个字符
r+=i;
strcpy(r,str3); //将str3写入新串
r+=len3;
p=q+len2; //将指针移到str2子串出现之后,准备下一次循环
}
else{ //表示剩余str1中已没有str2
strcpy(r,p);
break;
}
}
return s;
}
int main(){
char a[]="sabcababde",b[]="ab",c[]="efg",*d;
d=exchange(a,b,c);
printf("result= %s\n",d);
free(d);
return 0;
}
07 求自守数
题目描述:
自守数是指一个数的平方的尾数等于自身。例如,25就是—个自守数,因为252=625,末两位数为25;9376是一个自守数,因为93762=87909376.末4位数为9376。编写程序.从键盘输入整数m和n(10<m,n<200000),求出m与n之间所有的自守数,并且以每行5个数的形式输出。
思路:
如果一个自然数的平方数的尾部仍然为该自然数本身,则称其为自守数。
例如:
5 x 5 = 25
76 x 76 = 5776
625 x 625 = 390625
下面代码的目的是寻找出2千万以内的所有自守数。
注意,2千万的平方已经超出了整数表达的最大范围,所以该程序使用了一个巧妙的方案。
如果我们仔细观察乘法的计算过程,就会发现实际上对乘积的尾数有贡献的环节,从而不用真正计算出整个乘积。
分析手工方式下整数平方(乘法)的计算过程,以376为例:
376 被乘数
-
376 乘数
2256 第一个部分积=被乘数*乘数的倒数第一位
2632 第二个部分积=被乘数乘数的倒数第二位
1128 第三个部分积=被乘数乘数的倒数第三位
141376 积
本问题所关心的是积的最后三位。分析产生积的后三位的过程,可以看出,在每一次的部分积中,并不是它的每一位都会对积的后三位产生影响。
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void search(int a,int b){
if(a<10 || b>200000){
printf("范围超限!\n");
return ;
}
int temp,s,count=0;
int num;
for(num=a;num<b;num++){
temp=num; //保存初值
s=0;
while(1){
if(temp==0){
printf("%d ",num);
count++;
if(count%5==0)
printf("\n");
break;
}
int k=temp%10; //从末位开始,取出乘数的每一位
s+=k*num; //累计乘积
if(s%10!=k)
break;
s=s/10; //舍去累计乘积的末位
temp/=10;
}
}
}
int main()
{
int m,n;
while(scanf("%d %d",&m,&n)!=EOF){
if(m<=n)
search(m,n);
else
search(n,m);
}
return 0;
}
08 归并排序
归并排序包括"从上往下"和"从下往上"2种方式。
从下往上的归并排序:将待排序的数列分成若干个长度为1的子数列,然后将这些数列两两合并;得到若干个长度为2的有序数列,再将这些数列两两合并;得到若干个长度为4的有序数列,再将它们两两合并;直接合并成一个数列为止。这样就得到了我们想要的排序结果。(参考下面的图片)
从上往下的归并排序:它与"从下往上"在排序上是反方向的。它基本包括3步:
① 分解 – 将当前区间一分为二,即求分裂点 mid = (low + high)/2;
② 求解 – 递归地对两个子区间a[low…mid] 和 a[mid+1…high]进行归并排序。递归的终结条件是子区间长度为1。
③ 合并 – 将已排序的两个子区间a[low…mid]和 a[mid+1…high]归并为一个有序的区间a[low…high]。
相关理论:归并排序
int atemp[100];
void merge(int a[],int low,int mid,int high){
int i=low,j=mid+1,k=0; //k是指向临时数组
while(i<=mid && j<=high){
if(a[i]<a[j])
atemp[k++]=a[i++];
else
atemp[k++]=a[j++];
}
while(i<=mid)
atemp[k++]=a[i++];
while(j<=high)
atemp[k++]=a[j++];
for(i=low;i<high;i++)
a[i]=atemp[i];
}
void mergeSort(int a[],int low,int high){
if(low<high){
int mid=(low+high)/2;
mergeSort(a,low,mid);
mergeSort(a,mid+1,high);
merge(a,low,mid,high);
}
}
09 快速排序-查找第K小数
题目描述:
查找一个数组的第K小的数,注意同样大小算一样大。 如 2 1 3 4 5 2 第三小数为3。
输入:
输入有多组数据。 每组输入n,然后输入n个整数(1<=n<=1000),再输入k。
输出:
输出第k小的整数。
样例输入:
6
2 1 3 5 2 2
3
样例输出:
3
代码:
#include <stdio.h>
#include <stdlib.h>
#define N 1001
int partition2(int *a,int left,int right);
void quickSort(int *a, int left, int right);
int main()
{
int n,k,i;
int a[N];
while(scanf("%d",&n)!=EOF){
if(n<1 || n>1000)
break;
for(i=0;i<n;i++){
scanf("%d",&a[i]);
}
scanf("%d",&k);
//快速排序
quickSort(a,0,n-1);
//输出第k小数
for(i=1;i<n;i++){
if(a[i]>a[i-1])
k--;
if(k==0){
printf("%d\n",a[i]);
break;
}
}
}
return 0;
}
void quickSort(int *a, int left, int right){
int pivot;
if(left < right){
pivot=partition2(a,left,right);
quickSort(a,left,pivot-1);
quickSort(a,pivot+1,right);
}
}
int partition2(int *a,int left,int right){
int stand=left;
while(left<right){
while(left<right && stand<=a[right]){
right--;
}
if(left < right){
a[left++]=a[right];
}
while(left<right && a[left]<=stand){
left++;
}
if(left<right){
a[right--]=a[left];
}
}
a[left]=stand;
return left;
}
补充:找出数组中出现次数超过一半的元素
题目:找出数组中出现次数超过一半的元素(前提是该元素一定存在)
解法1:每次删除数组中两个不同的元素,删除后,要查找的那个元素的个数仍然超过删除后的元素总数的一半
解法2:如果数据量小,可以对数组进行排序,那么数组中间的数就是出现次数超过一半的数
#include <stdio.h>
int half_number(int a[], int n)
{
if( a == NULL || n <= 0 )
return -1;
int i, candidate;
int times = 0;
for( i=0; i<n; i++ )
{
if( times == 0 )
{
candidate = a[i];
times = 1;
}
else if( a[i] == candidate )
++times;
else
--times;
}
return candidate;
}
int main(void)
{
int a[] = {1,2,3,2,2,2,5,4,2};
int result = half_number(a, 9);
if( result != -1 )
printf("%d\n", result);
else
printf("Error.\n");
return 0;
}
该题的扩展:数组中有3个元素出现的次数都超过数组元素总数N的1/4, 找出这三个元素
解法:同上,但是每次删除4个互不相同的元素,处理上比上面的稍微麻烦
补充:二分查找
二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法。折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列;
首先分为两个过程,第一就是找到了,第二个就是没找到;
①:因为这个数组是排好序的,所以将当前的比较区间的中间值与key比较,key比中间值大,则说明key可能在数组的右半部分,否则在左半部分,一次递归,知道找到这个key为止;
②:就是没找到,只要low>=high就说明没有找到,因为当if条件不满足时,无法确实mid左右两边的high和low,不满足条件return返回-1,说明没有找到;
#include <stdio.h>
#define N 10
int a[N]={1,2,3,4,5,6,7,8,9,10};
int half(int left,int right,int x){
if(left<right){
int mid=(left+right)/2;
if(a[mid]==x)
return mid;
else if(a[mid]<key)
return half(left,mid-1,x);
else
return half(mid+1,right,x);
}
return -1;
}
int main(){
int key;
scanf("%d",&key);
int pos=half(0,N-1,key);
if(pos>=0){
printf("查找成功,该关键字位于数组的第%d个元素!\n",pos+1);
}
else{
printf("查找失败");
}
return 0;
}
补充:桶排序
桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。为了使桶排序更加高效,我们需要做到这两点:
- 在额外空间充足的情况下,尽量增大桶的数量
- 使用的映射函数能够将输入的 N 个数据均匀的分配到 K 个桶中
同时,对于桶中元素的排序,选择何种比较排序算法对于性能的影响至关重要。
- 什么时候最快
当输入的数据可以均匀的分配到每一个桶中。
- 什么时候最慢
当输入的数据被分配到了同一个桶中。
- 示意图
元素分布在桶中:
然后,元素在每个桶中排序:
补充:基数排序
基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。
- 基数排序 vs 计数排序 vs 桶排序
基数排序有两种方法:
这三种排序算法都利用了桶的概念,但对桶的使用方法上有明显差异:
- 基数排序:根据键值的每位数字来分配桶;
- 计数排序:每个桶只存储单一键值;
- 桶排序:每个桶存储一定范围的数值;
- LSD 基数排序动图演示
10 打牌问题
题目描述:
牌只有1到9,手里拿着已经排好序的牌a,对方出牌b,用程序判断手中牌是否能够压过对方出牌。
规则:出牌牌型有5种
[1]一张 如4 则5…9可压过
[2]两张 如44 则55,66,77,…,99可压过
[3]三张 如444 规则如[2]
[4]四张 如4444 规则如[2]
[5]五张 牌型只有12345 23456 34567 45678 56789五个,后面的比前面的均大。
输入:
输入有多组数据。
每组输入两个字符串(字符串大小不超过100)a,b。a字符串代表手中牌,b字符串代表出的牌。
输出:
压过输出YES 否则NO。
样例输入:
12233445566677 33
1122335566778899 12345
样例输出:
YES
YES
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 105
char a[N],b[6];
int main()
{
int len_a,len_b,i;
int c[N];
while(scanf("%s%s",a,b)!=EOF){
len_a=strlen(a);
len_b=strlen(b);
int flag=0;
memset(c,0,sizeof(c));
for(i=0;i<len_a;i++){
c[a[i]-'0']++;
}
if(len_b<5){
for(i=b[0]-'0'+1;i<10;i++){
if(c[i]>=len_b)
flag=1;
}
}
if(len_b==5){
for(i=b[0]-'0'+1;i<10;i++){
if(c[i] && c[i+1] && c[i+2] && c[i+3] && c[i+4])
flag=1;
}
}
if(flag==0)
printf("NO\n");
else
printf("YES\n");
}
return 0;
}
11 递推数列-矩阵幂
时间限制:1 秒 内存限制:32 兆 特殊判题:否
题目描述:
给定a0,a1,以及an=pa(n-1) + qa(n-2)中的p,q。这里n >= 2。 求第k个数对10000的模。
输入:
输入包括5个整数:a0、a1、p、q、k。
输出:
第k个数a(k)对10000的模。
样例输入:
20 1 1 14 5
样例输出:
8359
思路:
在按常规思路做这道题的时候,总是wrong answer或者Time Limit Exceed,这里需参考相关矩阵幂运算知识点,样例还可见《机试课程二》。
代码 1:
#include <stdio.h>
#include <stdlib.h>
#define N 100
int main()
{
int a[N];
int p,q,k;
int i;
scanf("%d%d%d%d%d",&a[0],&a[1],&p,&q,&k);
for(i=2;i<100;i++){
a[i]=((p*a[i-1])%10000)+((q*a[i-2])%10000);
}
printf("%d\n",a[k]);
return 0;
}
再次分析题目,可以发现递推式,
进而推出,
问题转化为,
这里要用到 矩阵二分乘法。
矩阵二分乘法是一种有效的快速计算矩阵幂的算法。
矩阵二分乘法通常可以将线性递推问题O(n)时间缩短到O(log(n))。
代码 2
#include <stdio.h>
#include <stdlib.h>
#define MOD 10000 //结果取MOD,避免高精度运算
/*将矩阵p与矩阵q相乘,结果存入p矩阵*/
void Matrix_mul(int p[2][2], int q[2][2])
{
int i, j, k;
int t[2][2]={0};
for(i = 0; i <= 1; i++)
for(j = 0; j <= 1; j++)
for(k = 0; k <= 1; k++)
t[i][j] += p[i][k] * q[k][j];
for(i = 0; i <= 1; i++)
for(j = 0; j <= 1; j++)
p[i][j] = t[i][j] % MOD;
}
/*计算p矩阵的n次方,结果存入p矩阵*/
void Matrix_cal(int p[2][2], int n)
{
int i, j;
int t[2][2];
for(i = 0; i <= 1; i++)
for(j = 0; j <= 1; j++)
t[i][j] = p[i][j];
if(n == 1)
return;
else if(n & 1)
{
Matrix_cal(p, n-1);
Matrix_mul(p, t);
}
else
{
Matrix_cal(p, n/2);
Matrix_mul(p, p);
}
}
int main()
{
int a0, a1, p, q, k;
while(scanf("%d%d%d%d%d", &a0, &a1, &p, &q, &k) != EOF)
{
if(k == 0)
printf("%d\n", a0);
else if(k == 1)
printf("%d\n", a1);
else
{
int matrix[2][2] = { {p%MOD, q%MOD}, {1, 0} };
Matrix_cal(matrix, k-1);
printf("%d\n", (a1 * matrix[0][0] + a0 * matrix[0][1]) % MOD);
}
}
return 0;
}
/**************************************************************
Problem: 1081
User: superlc320
Language: C++
Result: Accepted
Time:10 ms
Memory:1020 kb
***************************************************************/
代码 3
#include <stdio.h>
#define MOD 10000
typedef struct matrix{
int a00, a01, a10, a11;
}Matrix;
void MatrixMul(Matrix * m, Matrix * n){
Matrix tmp;
tmp.a00 = (m->a00 * n->a00 + m->a01 * n->a10) % MOD;
tmp.a01 = (m->a00 * n->a01 + m->a01 * n->a11) % MOD;
tmp.a10 = (m->a10 * n->a00 + m->a11 * n->a10) % MOD;
tmp.a11 = (m->a10 * n->a01 + m->a11 * n->a11) % MOD;
*m = tmp;
}
int main(void){
int a0, a1, p, q, k;
while (scanf ("%d%d%d%d%d",
&a0, &a1, &p, &q, &k) != EOF){
if (k == 0) {printf ("%d\n", a0 % MOD); continue;}
if (k == 1) {printf ("%d\n", a1 % MOD); continue;}
Matrix pq = {p%MOD, q%MOD, 1, 0};
Matrix ans = {1, 0, 0, 1};
--k;
while (k >= 1){
if ((k & 1) == 1)
MatrixMul (&ans, &pq);
MatrixMul (&pq, &pq);
k = k >> 1;
}
printf ("%d\n", (ans.a00*a1+ans.a01*a0) % MOD);
}
return 0;
}
---------------------
作者:It_BeeCoder
来源:CSDN
原文:https://blog.csdn.net/it_beecoder/article/details/70176270
版权声明:本文为博主原创文章,转载请附上博文链接!
12 数组最大数
输入一个四行五列的矩阵,找出每列最大的两个数。(华中科技大学真题)
题目描述:
输入第一行包括一个整数n(1<=n<=1000),接下来有n个四行每行包括五个整数。代表一个四行五列的矩阵,矩阵元素全部是整数。
输出描述:
可能有多组测试数据,对于每组数据,按照样例输出的格式将每列最大的两个数输出,如果最大的两个数中的一个数在这一列中有多个相同的值,则行值取行值小的那一个。
输出时要保留原矩阵的行列顺序,即在原矩阵中行值小的,在输出矩阵中的行值依然小。
样例输入:
2
1 2 4 9 8
-1 4 9 8 8
12 9 8 7 0
7 8 9 7 0
样例输出:
12 9 9 9 8
7 8 9 8 8
代码
#include <stdio.h>
#define row 4
#define column 5
void solve(int &r1, int &r2, int x){ //3个数的比较并排序
if(r1<r2){
if(x>r1){
r1=r2;
r2=x;
}
}
else if(r1>=r2){
if(x>r2){
r2=x;
}
}
}
int main()
{
int n,t,i,j;
int a[row][column],res[2][column];
while(scanf("%d",&n)!=EOF){
for(t=0;t<n;t++){
//获取一个4行5列的矩阵
for(i=0;i<row;i++){
for(j=0;j<column;j++){
scanf("%d",&a[i][j]);
//将前2行赋值给结果矩阵
if(i<2)
res[i][j]=a[i][j];
}
}
//遍历每一列,找出最大的两个数
for(i=0;i<column;i++){ //列
int r1=res[0][i];
int r2=res[1][i];
for(j=2;j<row;j++){ //行
//3个数的比较并排序
solve(r1,r2,a[j][i]);
}
res[0][i]=r1;
res[1][i]=r2;
}
//输出结果
for(i=0;i<2;i++){
for(j=0;j<column;j++)
printf("%d ",res[i][j]);
printf("\n");
}
}
}
return 0;
}
13 二叉树问题
01 题目描述:
由二叉树的先序和中序遍历,得出二叉树的后序遍历。第一行输入节点的个数,第二行输入先序序列,第三行输入中序序列,输出后序序列。
输入样例:
11
7 6 9 2 5 8 3 11 1 4 10
2 9 5 6 8 7 11 3 4 10 1
输出样例:
2 5 9 8 6 11 10 4 1 3 7
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define maxn 100
typedef struct node{
int data;
struct node *lchild; //指向左子树节点的指针
struct node *rchild; //指向右子树节点的指针
}BiTree;
int pre[maxn],in[maxn],post[maxn]; //先序,中序,后序
int n; //节点个数
//根据先序和中序重建二叉树
BiTree *create(int preL,int preR,int inL,int inR){
if(preL>preR)
return NULL;
//申请一个node型变量的地址空间
BiTree *root=(BiTree *)malloc(sizeof(BiTree));
root->data=pre[preL]; //结点权值为pre[0]
int k;
for(k=inL;k<=inR;k++){ //在中序中找到根节点的下标
if(in[k]==pre[preL])
break;
}
int numLeft=k-inL; //左子树结点个数
//递归构建左右子树
root->lchild=create(preL+1,preL+numLeft,inL,k-1);
root->rchild=create(preL+numLeft+1,preR,k+1,inR);
return root;
}
int num=0;
void postOrder(BiTree *root){
if(root==NULL)
return;
postOrder(root->lchild);
postOrder(root->rchild);
printf("%d",root->data);
num++;
if(num<n)
printf(" ");
}
int main()
{
int i;
scanf("%d",&n);
for(i=0;i<n;i++){
scanf("%d",&pre[i]);
}
for(i=0;i<n;i++){
scanf("%d",&in[i]);
}
BiTree *root=create(0,n-1,0,n-1);
postOrder(root);
printf("\n");
return 0;
}
02 题目描述:
给出二叉树的先序序列,实现二叉树左右子树的交换,并分别以先序、中序、后序输出
样例输入:
AB##C#D##
样例输出:
A C D B
D C A B
D C B A
思路:
创建树:
- 首先声明一个根结点bt,给系统输入一个字符,并进行,如果字符是’#’,则返回NULL;
- 如果字符不是’#’,则给根结点建立结点,并将刚输入的字符赋给该结点的数据域 ch ,之后将这个结点的的递归调用下一个结点赋给这个结点的左子树;
- 如果遇到输入的值为’#'时,这一次递归调用结束,返回上一层递归调用,接着继续执行循环将这一次结点的递归调用;
- 如果遇到不是’#‘就继续执行第2步,遇到’#'返回NULL,直到输入完所要创建的结点,并将根结点bt返回到main函数,再按回车就会执行出结果;
交换操作:
-
首先进行判断,只要这个结点不为根结点,就会进行判断;
-
从根结点开始,访问一个结点就会交换结点的左右子树;
-
之后判断交换后的左右子树是否为空,如果左子树不为空,继续访问这个结点的左子树,进行递归调用,重复上述步骤;
-
如果为空,判断这个结点的右子树是否为空,不为空,进行递归调用,为空的话结束交换Exchange函数,返回上一层递归调用;
-
直到访问完所有结点返回main函数,进行其他操作;
#include <stdio.h>
#include <stdlib.h>//二叉树的结点类型
typedef struct tree{
char ch;
struct tree *lchild;
struct tree *rchild;
}BitTree;//创建树
BitTree *CreatTree(){
BiTree *bt;
char str;
scanf("%c",&str);
if(str==’#’)
return NULL;
else{
bt=(BiTree *)malloc(sizeof(BitTree));
bt->ch=str;
bt->lchild=CreatTree();
bt->rchild=CreatTree();
return bt;
}
}//交换左右二叉树
void Exchange(BitTree *bt){
if(bt==NULL)
return ;
else{
//交换左右子树
BitTree *temp=bt->lchild;
bt->lchild=bt->rchild;
bt->rchild=temp;
Exchange(bt->lchild);
Exchange(bt->rchild);
}
}//先序输出交换后的二叉树
void PreOrder(BitTree *bt){
if(bt!=NULL){
printf("%c “,bt->ch);
PreOrder(bt->lchild);
PreOrder(bt->rchild);
}
}
//中序输出交换后的二叉树
void InOrder(BitTree *bt){
if(bt!=NULL){
InOrder(bt->lchild);
printf(”%c “,bt->ch);
InOrder(bt->rchild);
}
}
//后序输出交换后的二叉树
void PostOrder(BitTree *bt){
if(bt!=NULL){
PostOrder(bt->lchild);
PostOrder(bt->rchild);
printf(”%c ",bt->ch);
}
}int main(){
BitTree *bt;
//创建二叉树
printf(“请以先序序列输入需要交换的二叉树:\n”);
bt=CreatTree();
//交换左右子树
Exchange(bt);
//先序输出
printf(“交换后以先序序列输出:\n”);
PreOrder(bt);
printf("\n");
//中序输出
printf(“交换后以中序序列输出:\n”);
InOrder(bt);
printf("\n");
//后序输出
printf(“交换后以后序序列输出:\n”);
PostOrder(bt);
printf("\n");
return 0;
}
14 报数–链表
题目描述:
有n个人围成一圈,顺序排号。从第1个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号人。
代码 1:
#include <stdio.h>
#define N 50
int main(){
int i,n,pep[N],*p;
int m,count;
scanf("%d",&n);
p=pep;
for(i=0;i<n;i++){
*(p+i)=i+1; //以1-n为序给人员编号
}
i=0; //i为每次循环时的计数变量
m=0; //m为退出人数
count=0; //count为按1,2,3报数的计数变量
while(m<n-1){
if(*(p+i)!=0)
count++;
if(count==3){
m++;
*(p+i)=0; //退出的人编号置为0
count=0;
}
i++;
if(i==n)
i=0; //报数到尾后,恢复为数组头
}
while(*p==0)
p++;
printf("%d\n",*p);
return 0;
}
代码 2(链表法)
#include <stdio.h>
#define N 13
struct person{
int number;
int nextp;
}link[N+1];
int main(){
int i,count,h;
for(i=1;i<=N;i++){
link[i].number=i;
if(i==N)
link[i].nextp=1; //构建循环链表
else
link[i].nextp=i+1;
}
count=0;
h=N;
printf("成员离开序号:\n");
while(count<N-1){
i=0;
while(i!=3){
h=link[h].nextp; //成员下标
if(link[h].number!=0)
i++;
}
printf("%4d",link[h].number);
link[h].number=0;
count++;
}
printf("\n最后留下的是:");
for(i=1;i<=N;i++){
if(link[i].number)
printf("%d\n",link[i].number);
}
return 0;
}
15 栈的应用–括号匹配问题
题目描述:
在某个字符串(长度不超过 100)中有左括号、右括号和大小写字母;规定(与常见的算数式子一样)任何一个左括号都从内到外与在它右边且距离最近的右括号匹配。写一个程序,找到无法匹配的左括号和右括号,输出原来字符串,并在下一行标出不能匹配的括号。不能匹配的左括号用"$“标注,不能匹配的右括号用”?"标注.
输入:
输入包括多组数据,每组数据一行,包含一个字符串,只包含左右括号和大小写字母,字符串长度不超过 100。
输出:
对每组输出数据,输出两行,第一行包含原始输入字符,第二行由" “和”?"表示与之对应的左括号和右括号不能匹配。
样例输入:
)(rttyy())sss)(
样例输出:
)(rttyy())sss)(
? ?$
思路:
若我们按照从左至右的顺序遍历字符串,并将遇到的所有左括号都放入堆栈中等待匹配;若在遍历过程中遇到一个右括号,由于按照从左向右的顺序遍历字符串,若此时堆栈非空,那么栈顶左括号即为与其匹配的左括号;相反,若堆栈为空,则表示在其之前不存在未被匹配的左括号,匹配失败。
代码 :
#include <iostream>
#include <stack>
using namespace std;
stack<int> S; //定义一个堆栈
char str[110]; //保存输入字符串
char ans[110]; //保存输出字符串
int main()
{
while(scanf("%s",str)!=EOF){
int i;
for(i=0;str[i]!=0;i++){
if(str[i]=='('){ //若遇到左括号
S.push(i); //将其数组下标放入堆栈中
ans[i]=' '; //暂且将对应的输出字符串位置改为空格
}
else if(str[i]=')'){ //若遇到右括号
if(S.empty()==false){ //若此时堆栈为非空
S.pop(); //栈顶位置左括号与其匹配,从战中弹出该已经匹配的左括号
ans[i]=' '; //修改输出中该位置为空格
}
else
ans[i]='?'; //若堆栈为空,则无法找到匹配,修改输出中该位置为?
}
else
ans=' '; //若其为其它字符,与括号匹配无关,修改输出为空格
}
while(!S.empty()){ //当字符串遍历完成后,尚留在堆栈中的左括号无法匹配
ans[S.top()]='$';
S.pop(); //弹出
}
ans[i]=0; //为了使输出形成字符串,在其最后一个字符后添加一个空字符
puts(str);
puts(ans);
}
return 0;
}
16 哈夫曼树
题目描述:
哈夫曼树,第一行输入一个数 n,表示叶结点的个数。需要用这些叶结点生成哈夫曼树,根据哈夫曼树的概念,这些结点有权值,即 weight,题目需要输出所有结点的值与权值的乘积之和。
输入:
输入有多组数据。每组第一行输入一个数 n,接着输入 n 个叶节点(叶节点权值不超过 100,2<=n<=1000)。
输出:
输出权值。
样例输入:
5
1 2 2 5 9
样例输出:
37
代码:
#include <iostream>
#include <queue>
#include <stdio.h>
using namespace std;
priority_queue<int, vector<int>,greater<int> >Q; //建立一个小顶堆
int main()
{
int n;
while(scanf("%d",&n)!=EOF){
while(Q.empty()==false)
Q.pop(); //清空堆中元素
for(int i=1;i<=n;i++){
int x;
scanf("%d",&x);
Q.push(x); //将权值放入堆中
}
int ans=0;
while(Q.size()>1){
int a=Q.top();
Q.pop();
int b=Q.top();
Q.pop();
ans+=a+b; //该父节点必为非叶子节点,故累加其权值
Q.push(a+b); //将双亲结点的权值放入堆中
}
printf("%d\n",ans);
}
return 0;
}
17 define与定义函数的区别
题目:输入三个整数x,y,z,请把这三个数由小到大输出。
代码 1:
#include <stdio.h>
#define swap(a,b) {a=a+b;b=a-b;a=a-b;}
int main()
{
int x,y,z;
printf("请输入三个数字:");
scanf("%d %d %d",&x,&y,&z);
if(x>y)
{
swap(x,y);
}
if(x>z)
{
swap(x,z);
}
if(y>z)
{
swap(y,z);
}
printf("从小到大排序:%d %d %d\n",x,y,z);
return 0;
}
代码 2
#include <stdio.h>
void swap(int *a,int *b){ //*a代表指针变量a,a存储的是地址,*a是地址的值
int temp;
temp=*a;
*a=*b;
*b=temp;
}
int main(){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
if(x>y)
swap(&x,&y);
if(x>z)
swap(&x,&z);
if(y>z)
swap(&y,&z);
printf("从小到大排序:%d %d %d\n",x,y,z);
return 0;
}