複試機試 -- 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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章