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