复试机试 -- C语言习题

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;
}

补充:桶排序

桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。为了使桶排序更加高效,我们需要做到这两点:

  1. 在额外空间充足的情况下,尽量增大桶的数量
  2. 使用的映射函数能够将输入的 N 个数据均匀的分配到 K 个桶中

同时,对于桶中元素的排序,选择何种比较排序算法对于性能的影响至关重要。

  1. 什么时候最快

当输入的数据可以均匀的分配到每一个桶中。

  1. 什么时候最慢

当输入的数据被分配到了同一个桶中。

  1. 示意图

元素分布在桶中:

然后,元素在每个桶中排序:

补充:基数排序

基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。

  1. 基数排序 vs 计数排序 vs 桶排序

基数排序有两种方法:

这三种排序算法都利用了桶的概念,但对桶的使用方法上有明显差异:

  • 基数排序:根据键值的每位数字来分配桶;
  • 计数排序:每个桶只存储单一键值;
  • 桶排序:每个桶存储一定范围的数值;
  1. 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

思路:

创建树:

  1. 首先声明一个根结点bt,给系统输入一个字符,并进行,如果字符是’#’,则返回NULL;
  2. 如果字符不是’#’,则给根结点建立结点,并将刚输入的字符赋给该结点的数据域 ch ,之后将这个结点的的递归调用下一个结点赋给这个结点的左子树;
  3. 如果遇到输入的值为’#'时,这一次递归调用结束,返回上一层递归调用,接着继续执行循环将这一次结点的递归调用;
  4. 如果遇到不是’#‘就继续执行第2步,遇到’#'返回NULL,直到输入完所要创建的结点,并将根结点bt返回到main函数,再按回车就会执行出结果;

交换操作:

  1. 首先进行判断,只要这个结点不为根结点,就会进行判断;

  2. 从根结点开始,访问一个结点就会交换结点的左右子树;

  3. 之后判断交换后的左右子树是否为空,如果左子树不为空,继续访问这个结点的左子树,进行递归调用,重复上述步骤;

  4. 如果为空,判断这个结点的右子树是否为空,不为空,进行递归调用,为空的话结束交换Exchange函数,返回上一层递归调用;

  5. 直到访问完所有结点返回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。

输出:

对每组输出数据,输出两行,第一行包含原始输入字符,第二行由" &quot; , &quot; ? &quot; &quot; &quot;,&quot;?&quot;和空格组成,&quot; “和”?"表示与之对应的左括号和右括号不能匹配。

样例输入:

)(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;
}

猜你喜欢

转载自blog.csdn.net/Ronnyz/article/details/89467794