1. 程式人生 > >演算法初步之排序

演算法初步之排序

     這一小節的內容都是排序,排序所能涉及到的內容很多。在這些題目中,冒泡,選擇排序偶爾會用到。因為涉及到的資料量並不大,因此不會超時。多數情況下,呼叫sort函式可以解決大部分需要排序的東西。sort內部採用類似快速排序的的機制運作,很少會超時。還有就是在操作字串的時候,很多細節還是要注意,否則很容易遇到莫名其妙的執行錯誤。這一節的題目比較簡單,接下來是這一節的九道題目。

問題A:

題目描述

對輸入的n個數進行排序並輸出。

輸入

輸入的第一行包括一個整數n(1<=n<=100)。 接下來的一行包括n個整數。

輸出

可能有多組測試資料,對於每組資料,將排序後的n個整數輸出,每個數後面都有一個空格。
每組測試資料的結果佔一行。

樣例輸入

5
5 4 3 1 2

樣例輸出

1 2 3 4 5 

#include<cstdio>
int main(){
    int n;
    while(scanf("%d",&n)!=-1){
        //只有不到100個數,先試一下選擇排序
        //依次從剩下的元素中找到最小(大)的元素
        //設計為先,很重要。根據思路去敲程式碼,而不是瞎搞,浪費時間
        //流程很重要,remember
        int a[103];
        int i;
        for(i=0;i<n;i++){
            scanf("%d",&a[i]);
        }
        for(i=0;i<n;i++)
        for(int j=i;j<n;j++){
            if(a[j]<=a[i]){
                int temp=a[i];
                a[i]=a[j];
                a[j]=temp;
            }
        }
        for(i=0;i<n;i++)
        printf("%d ",a[i]);
        printf("\n");
    }
    return 0;
}
 

問題B:

題目描述

輸入一系列整數,將其中最大的數挑出,並將剩下的數進行排序。

輸入

輸入第一行包括1個整數N,1<=N<=1000,代表輸入資料的個數。

接下來的一行有N個整數。

輸出

可能有多組測試資料,對於每組資料,

第一行輸出一個整數,代表N個整數中的最大值,並將此值從陣列中去除,將剩下的數進行排序。

第二行將排序的結果輸出。

樣例輸入

5
5 3 2 4 1

樣例輸出

5
1 2 3 4

提示

如果陣列中只有一個數,當第一行將其輸出後,第二行請輸出"-1"。

#include<cstdio>
#include<cstring>

const int M=1005;
int main(){
    //處理只有一個數字的情況:第一行數字,第二行-1
    //處理有N個數字的情況 :第一行最大數,第二行其餘數字的升序
    //1~1000
    //資料範圍小就是好做
    int n,a[M];
    while(scanf("%d",&n)!=-1){
        if(n==1){
            scanf("%d",&a[0]);
            printf("%d\n",a[0]);
            printf("-1\n");
        }
        else{
            int i;
            for(i=0;i<n;i++){
                scanf("%d",&a[i]);
            }
            for(i=0;i<n;i++)
            for(int j=i;j<n;j++){
                if(a[i]>=a[j]){
                    int temp=a[i];
                    a[i]=a[j];
                    a[j]=temp;
                    
                }
            }
            printf("%d\n",a[n-1]);
            for(i=0;i<n-1;i++){
                printf("%d ",a[i]);
            }
            printf("\n");
        }
        memset(a,0,sizeof(a));
    }
    return 0;
}

問題C:

題目描述

Excel可以對一組紀錄按任意指定列排序。現請你編寫程式實現類似功能。

對每個測試用例,首先輸出1行“Case i:”,其中 i 是測試用例的編號(從1開始)。隨後在 N 行中輸出按要求排序後的結果,即:當 C=1 時,按學號遞增排序;當 C=2時,按姓名的非遞減字典序排序;當 C=3 時,按成績的非遞減排序。當若干學生具有相同姓名或者相同成績時,則按他們的學號遞增排序。

輸入

測試輸入包含若干測試用例。每個測試用例的第1行包含兩個整數 N (N<=100000) 和 C,其中 N 是紀錄的條數,C 是指定排序的列號。以下有N行,每行包含一條學生紀錄。每條學生紀錄由學號(6位數字,同組測試中沒有重複的學號)、姓名(不超過8位且不包含空格的字串)、成績(閉區間[0, 100]內的整數)組成,每個專案間用1個空格隔開。當讀到 N=0 時,全部輸入結束,相應的結果不要輸出。

輸出

對每個測試用例,首先輸出1行“Case i:”,其中 i 是測試用例的編號(從1開始)。隨後在 N 行中輸出按要求排序後的結果,即:當 C=1 時,按學號遞增排序;當 C=2時,按姓名的非遞減字典序排序;當 C=3 時,按成績的非遞減排序。當若干學生具有相同姓名或者相同成績時,則按他們的學號遞增排序。

樣例輸入

4 1
000001 Zhao 75
000004 Qian 88
000003 Li 64
000002 Sun 90
4 2
000005 Zhao 95
000011 Zhao 75
000007 Qian 68
000006 Sun 85
4 3
000002 Qian 88
000015 Li 95
000012 Zhao 70
000009 Sun 95
0 3

樣例輸出

Case 1:
000001 Zhao 75
000002 Sun 90
000003 Li 64
000004 Qian 88
Case 2:
000007 Qian 68
000006 Sun 85
000005 Zhao 95
000011 Zhao 75
Case 3:
000012 Zhao 70
000002 Qian 88
000009 Sun 95
000015 Li 95

#include<cstdio>
#include<algorithm>
#include<cstring>

const int M=100009;
typedef struct {
    char num[10];
    char name[10];
    int grade;
}students;
students s[M];
bool cmp(students a,students b){
    return strcmp(a.num,b.num)<0;        //remeber this
}                                        //具體實現以後再看
bool cmp1(students a,students b){
    if(!strcmp(a.name,b.name))
    return strcmp(a.num,b.num)<0;
    else
    return strcmp(a.name,b.name)<0;      
}
bool cmp2(students a,students b){
    if(a.grade==b.grade)
    return strcmp(a.num,b.num)<0;
    else
    return a.grade<b.grade ;
}
int  main(){
    //選擇,快速,希爾,桶,奇偶,冒泡,歸併
    /*排序有要求
               1:學號遞增(衝突時優先)
               2:姓名非遞減
               3:分數非遞減    */
    /*資料輸入,輸出格式
            N是記錄條數,C是排序選擇
            依次6位學號,8位連續姓名,【0,100】的分數
            N位0時程式結束*/
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    int i,n,c,t=0;
    while(scanf("%d%d",&n,&c)!=-1&&n!=0){
            for(i=0;i<n;i++){
                scanf("%s%s%d",s[i].num,s[i].name,&s[i].grade);
            
            }
            switch(c){
                case 1:std::sort(s,s+n,cmp);
                break;
                case 2:std::sort(s,s+n,cmp1);
                break;
                case 3:std::sort(s,s+n,cmp2);
                break;
            }
        t++;
        printf("Case %d:\n",t);
        for(i=0;i<n;i++)
        printf("%s %s %d\n",s[i].num,s[i].name,s[i].grade);
        memset(s,0,sizeof(s));
    }
    return 0;
}

問題D:

題目描述

輸入一個字串,長度小於等於200,然後將輸出按字元順序升序排序後的字串。

輸入

測試資料有多組,輸入字串。

輸出

對於每組輸入,輸出處理後的結果。

樣例輸入

tianqin

樣例輸出

aiinnqt

提示

注意輸入的字串中可能有空格。

#include<cstdio>
#include<algorithm>
#include<cstring>

bool cmp(char a,char b){
    return a<b;
}
int  main(){
    //每次都要分析題目後寫設計思路
     //輸入長度小於200的字串,對其排序後輸出
     //排序選擇:字元陣列內部排序(考慮空格情況) ,如果不給提示,第一次應該想不到
     //不會,字串都是些什麼玩意兒
     //試一下: 假設全是小寫字母,我理解的是輸出不含空格
     //這道題簡直實在侮辱 ,什麼玩意兒
      char a[205],b[205];
      while(gets(a)!=NULL){
          int i,j,l=strlen(a);
          for(i=0,j=0;i<l;i++){
              if(a[i])
              b[j++]=a[i];
          }
          int ll=strlen(b);
          std::sort(b,b+ll,cmp);
          printf("%s\n",b);
          memset(b,0,sizeof(b));
      }
    return 0;
}

問題E:

題目描述

請寫一個程式,對於一個m行m列的(1<m<10)的方陣,求其每一行,每一列及主對角線元素之和,最後按照從大到小的順序依次輸出。

輸入

共一組資料,輸入的第一行為一個正整數,表示m,接下來的m行,每行m個整數表示方陣元素。

輸出

從大到小排列的一行整數,每個整數後跟一個空格,最後換行。

樣例輸入

4
15 8 -2 6
31 24 18 71
-3 -9 27 13
17 21 38 69

樣例輸出

159 145 144 135 81 60 44 32 28 27

#include<cstdio>
#include<algorithm>
#include<cstring>

bool cmp(int a,int b){
    return a>b;
}
int  main(){
    //分析:輸入m行m列的矩陣(整數,1<m<10)
    //計算行,列,主隊角元素之和
    //對計算出的數字排序,需要控制個數m+m+1+1,然後輸出
    
    //測試只對一半(在下一次計算時,清空陣列)              (什麼叫測試資料範圍)
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    int m,a[10][10],sum[22];
    while(scanf("%d",&m)!=-1 ){         //忘了寫-1而導致輸出超限
        memset(a,0,sizeof(a));
        memset(sum,0,sizeof(sum));
    int i,j ;
    for(i=0;i<m;i++)
    for(j=0;j<m;j++){
        scanf("%d",&a[i][j]);
        sum[i]+=a[i][j];                  //m行數字的和
    }
    for(j=0;j<m;j++)
    for(i=0;i<m;i++){
        sum[m+j]+=a[i][j];                //m列數字的和
    }
    for(i=0;i<m;i++){                     //對角線元素之和
    sum[m+m]+=a[i][i];
    sum[m+m+1]+=a[i][m-1-i];
}
    std::sort(sum,sum+m+m+1+1,cmp);
    for(i=0;i<m+m+1;i++)
    printf("%d ",sum[i]);
    printf("%d\n",sum[m+m+1]);
}
    return 0;
}

問題F:

題目描述

N只小白鼠(1 <= N <= 100),每隻鼠頭上戴著一頂有顏色的帽子。現在稱出每隻白鼠的重量,要求按照白鼠重量從大到小的順序輸出它們頭上帽子的顏色。帽子的顏色用“red”,“blue”等字串來表示。不同的小白鼠可以戴相同顏色的帽子。白鼠的重量用整數表示。

輸入

多案例輸入,每個案例的輸入第一行為一個整數N,表示小白鼠的數目。

下面有N行,每行是一隻白鼠的資訊。第一個為不大於100的正整數,表示白鼠的重量,;第二個為字串,表示白鼠的帽子顏色,字串長度不超過10個字元。

注意:白鼠的重量各不相同。

輸出

每個案例按照白鼠的重量從大到小的順序輸出白鼠的帽子顏色。

樣例輸入

1
79 omi
9
46 lcg
92 cru
37 ceq
54 vhr
17 wus
27 tnv
13 kyr
95 wld
34 qox

樣例輸出

omi
wld
cru
vhr
lcg
ceq
qox
tnv
wus
kyr

#include<cstdio>
#include<algorithm>
#include<cstring>

int  main(){
    //N(1~100)個小白鼠,兩個值:重量(小等於100)和顏色(十個字元)
    //對重量排序,輸出顏色
    //二維陣列,排序怎麼辦?
    //關鍵點:白鼠的重量各不相同,可以採用那個方法,暫時忘記名字
    //執行奔潰  :char*定義常量字串,不能改變
    //兩個陣列:放重量,放顏色,再新增一個數組來排序
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    int n;
    while(scanf("%d",&n)!=-1)  {
        char a[101][10];
        int w[101],t[101];
        memset(a,0,sizeof(a));
        memset(w,0,sizeof(w));
        memset(t,0,sizeof(t));
        int i,j;
        for(i=0;i<n;i++){
            scanf("%d",&w[i]);
            scanf("%s",a[w[i]]);
            t[w[i]]=1;
        //    printf("%s",a[w[i]]);
        }
        
        for(j=100;j>=0;j--)
            if(t[j]==1)             //這裡會打出多餘的換行
        printf("%s\n",a[j]);
    }
    return 0;
}

問題G:

題目描述

中位數定義:一組資料按從小到大的順序依次排列,處在中間位置的一個數(或最中間兩個資料的平均數).
給出一組無序整數,求出中位數,如果求最中間兩個數的平均數,向下取整即可(不需要使用浮點數)

輸入

該程式包含多組測試資料,每一組測試資料的第一行為N,代表該組測試資料包含的資料個數,1<=N<=10000.
接著N行為N個數據的輸入,N=0時結束輸入

輸出

輸出中位數,每一組測試資料輸出一行

樣例輸入

1
468
15
501
170
725
479
359
963
465
706
146
282
828
962
492
996
943
0

樣例輸出

468
501

#include<cstdio>
#include<algorithm>
#include<cstring>
const int M=10003;

//int cmp(const void* a,const void *b){
//    return *(int*)a-*(int*)b;
bool cmp(int a,int b){
    return a<b;
}
int  main(){
    //分析:找出中位數(整數,向下取整)
    //輸入:N位0時結束(1~10000)
    //排序: 待定
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
     int n,a[M];
     while(scanf("%d",&n)&&n!=0){
         memset(a,0,sizeof(a));
         int i;
         for(i=0;i<n;i++){
             scanf("%d",&a[i]);
         }
    //    qsort(a,n,sizeof(int),cmp);        //系統禁止呼叫這個玩意兒
    std::sort(a,a+n,cmp);                   //呼叫sort函式不會超時
        if(n%2==1)
        printf("%d\n",a[n/2]);
        else{
            int temp=(a[n/2]+a[(n-1)/2])/2;//自動去掉小數部分
            printf("%d\n",temp);
        }
     }
    return 0;
}

問題H:

題目描述

輸入10個整數,彼此以空格分隔。重新排序以後輸出(也按空格分隔),要求:
1.先輸出其中的奇數,並按從大到小排列;
2.然後輸出其中的偶數,並按從小到大排列。

輸入

任意排序的10個整數(0~100),彼此以空格分隔。

輸出

可能有多組測試資料,對於每組資料,按照要求排序後輸出,由空格分隔。

樣例輸入

0 56 19 81 59 48 35 90 83 75 
17 86 71 51 30 1 9 36 14 16 

樣例輸出

83 81 75 59 35 19 0 48 56 90
71 51 17 9 1 14 16 30 36 86

提示


多組資料,注意輸出格式


1. 測試資料可能有很多組,請使用while(cin>>a[0]>>a[1]>>...>>a[9])類似的做法來實現;

2. 輸入資料隨機,有可能相等。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

bool cmp1(int a,int b){
    return a>b;
}
bool cmp2(int a,int b){
    return a<b;
}
int  main(){
    //輸入:十個整數
    //輸出:奇數從大到小,偶數從小到大,一行,空格分開
    //這個和之前的資料讀入不一樣,每次讀一組,按照提示的方法寫
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    int a[10],odd[10],even[10]; //空間換時間
    while(cin>>a[0]>>a[1]>>a[2]>>a[3]>>a[4]>>a[5]>>a[6]>>a[7]>>a[8]>>a[9]) {     //提示1
         int i,t1=0,t2=0;
         memset(odd,0,sizeof(odd));
         memset(even,0,sizeof(even));
         for(i=0;i<10;i++){
             if(a[i]%2==0)
             even[t2++]=a[i];
             else
             odd[t1++]=a[i];
             
         }
         sort(odd,odd+t1,cmp1);
         sort(even,even+t2,cmp2);
         for(i=0;i<t1;i++)
         cout<<odd[i]<<" ";
         for(i=0;i<t2;i++)
         cout<<even[i]<<" ";
         cout<<endl;
    }
    return 0;
}

問題I:

題目描述

今天的上機考試雖然有實時的Ranklist,但上面的排名只是根據完成的題數排序,沒有考慮每題的分值,所以並不是最後的排名。給定錄取分數線,請你寫程式找出最後通過分數線的考生,並將他們的成績按降序列印。

輸入

測試輸入包含若干場考試的資訊。每場考試資訊的第1行給出考生人數N ( 0 < N < 1000 )、考題數M ( 0 < M < = 10 )、分數線(正整數)G;第2行排序給出第1題至第M題的正整數分值;以下N行,每行給出一名考生的准考證號(長度不超過20的字串)、該生解決的題目總數m、以及這m道題的題號(題目號由1到M)。 
當讀入的考生人數為0時,輸入結束,該場考試不予處理。

輸出

對每場考試,首先在第1行輸出不低於分數線的考生人數n,隨後n行按分數從高到低輸出上線考生的考號與分數,其間用1空格分隔。若有多名考生分數相同,則按他們考號的升序輸出。

樣例輸入

3 5 32
17 10 12 9 15
CS22003 5 1 2 3 4 5
CS22004 3 5 1 3
CS22002 2 1 5
0

樣例輸出

3
CS22003 63
CS22004 44
CS22002 32

提示


這題比較簡單,計算好每個人的分數後按題目要求排序即可。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

const int N=1005;
const int M=15;

struct students{
    char admission[20];
    int total;
    int topic[M];
    int sum;
}s[N];
bool cmp(students a,students b){
    if(a.sum==b.sum)
    return strcmp(a.admission,b.admission)<0;
    else
    return a.sum>b.sum;
}
int  main(){
    //輸入:人數 N ( 0 < N < 1000 )、考題數M ( 0 < M < = 10 )、分數線(正整數)G
    //第2是第1題至第M題的正整數分值;
    //以下N行,考生的准考證號(長度不超過20的字串)、解決的題目總數m、以及這m道題的題號(題目號由1到M)。
    //考生人數為0時,輸入結束
    //輸出: 第1行輸出不低於分數線的考生人數n,
    //隨後n行按分數從高到低輸出上線考生的考號與分數,其間用1空格分隔。
    //若有多名考生分數相同,則按他們考號的升序輸出。
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    int n,m,g,i;
    int questions[M];
    while(scanf("%d",&n)&&n!=0) {
        memset(questions,0,sizeof(questions));
        int t=0;
        scanf("%d%d",&m,&g);
        for(i=1;i<=m;i++){
            scanf("%d",&questions[i]);
        }
        for(i=0;i<n;i++){
            scanf("%s%d",s[i].admission,&s[i].total);
            for(int j=0;j<s[i].total;j++){
                scanf("%d",&s[i].topic[j]);
                s[i].sum+=questions[s[i].topic[j]];
            }
            if(s[i].sum>=g){
                t++;
            }
        }
    std::    sort(s,s+n,cmp);
    printf("%d\n",t);
         for(i=0;i<n;i++){
             if(s[i].sum>=g){
                 printf("%s %d\n",s[i].admission,s[i].sum);
             }
             
         }
        
    }
    return 0;
}